]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #67055 - lqd:const_qualif, r=oli-obk
authorMazdak Farrokhzad <twingoow@gmail.com>
Thu, 5 Dec 2019 18:03:21 +0000 (19:03 +0100)
committerGitHub <noreply@github.com>
Thu, 5 Dec 2019 18:03:21 +0000 (19:03 +0100)
Make const-qualification look at more `const fn`s

As explained in a lot more detail in #67053 this makes const-qualification not ignore the unstable const fns in libcore.

r? @oli-obk cc @ecstatic-morse

(Still a bit unsure about the `cfg`s here, for bootstrapping, does that seem correct ?)

Fixes #67053.

97 files changed:
Cargo.lock
src/liballoc/rc.rs
src/liballoc/sync.rs
src/libcore/str/mod.rs
src/libcore/sync/atomic.rs
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/error_reporting/note.rs
src/librustc/ty/print/pretty.rs
src/librustc_codegen_llvm/back/write.rs
src/librustc_codegen_llvm/llvm/ffi.rs
src/librustc_mir/borrow_check/conflict_errors.rs [deleted file]
src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/find_use.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/mod.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/move_errors.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/region_errors.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/region_name.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/diagnostics/var_name.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/error_reporting.rs [deleted file]
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/move_errors.rs [deleted file]
src/librustc_mir/borrow_check/mutability_errors.rs [deleted file]
src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs [deleted file]
src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs [deleted file]
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs [deleted file]
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs [deleted file]
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs [deleted file]
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs [deleted file]
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_parse/Cargo.toml
src/librustc_parse/config.rs
src/librustc_parse/lexer/mod.rs
src/librustc_parse/lexer/tokentrees.rs
src/librustc_parse/lexer/unicode_chars.rs
src/librustc_parse/lib.rs
src/librustc_parse/parser/attr.rs
src/librustc_parse/parser/diagnostics.rs
src/librustc_parse/parser/expr.rs
src/librustc_parse/parser/generics.rs
src/librustc_parse/parser/item.rs
src/librustc_parse/parser/mod.rs
src/librustc_parse/parser/module.rs
src/librustc_parse/parser/pat.rs
src/librustc_parse/parser/path.rs
src/librustc_parse/parser/stmt.rs
src/librustc_parse/parser/ty.rs
src/librustc_parse/validate_attr.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/expr.rs
src/librustc_typeck/check/pat.rs
src/libsyntax_pos/symbol.rs
src/rustllvm/PassWrapper.cpp
src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
src/test/ui/c-variadic/variadic-ffi-4.stderr
src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
src/test/ui/issues/issue-16683.stderr
src/test/ui/issues/issue-17758.stderr
src/test/ui/issues/issue-20831-debruijn.stderr
src/test/ui/issues/issue-52213.stderr
src/test/ui/issues/issue-55796.stderr
src/test/ui/issues/issue-65634-raw-ident-suggestion.rs [new file with mode: 0644]
src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr [new file with mode: 0644]
src/test/ui/issues/issue-66702-break-outside-loop-val.rs [new file with mode: 0644]
src/test/ui/issues/issue-66702-break-outside-loop-val.stderr [new file with mode: 0644]
src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs [new file with mode: 0644]
src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr [new file with mode: 0644]
src/test/ui/nll/issue-55394.stderr
src/test/ui/nll/normalization-bounds-error.stderr
src/test/ui/nll/type-alias-free-regions.stderr
src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
src/test/ui/parser/raw/raw-literal-keywords.rs
src/test/ui/parser/raw/raw-literal-keywords.stderr
src/test/ui/regions/region-object-lifetime-in-coercion.stderr
src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
src/test/ui/regions/regions-close-object-into-object-2.stderr
src/test/ui/regions/regions-close-object-into-object-4.stderr
src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
src/test/ui/regions/regions-creating-enums4.stderr
src/test/ui/regions/regions-escape-method.stderr
src/test/ui/regions/regions-escape-via-trait-or-not.stderr
src/test/ui/regions/regions-nested-fns.stderr
src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
src/test/ui/regions/regions-ret-borrowed-1.stderr
src/test/ui/regions/regions-ret-borrowed.stderr
src/test/ui/regions/regions-trait-object-subtyping.stderr
src/test/ui/reject-specialized-drops-8142.stderr
src/test/ui/suggestions/raw-name-use-suggestion.rs
src/test/ui/suggestions/raw-name-use-suggestion.stderr
src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr

index 5e83513af5b377171d1e9cb282c03720b4478cf6..26727c5c1db6039702653ed28a54400d13211777 100644 (file)
@@ -3806,7 +3806,6 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_lexer",
- "rustc_target",
  "smallvec 1.0.0",
  "syntax",
  "syntax_pos",
index 2254cde7f49cca749837f767ec46f1fc77256e98..1ff1c3c834f4ea4c10b3ed5133ec765601f040bf 100644 (file)
@@ -1648,10 +1648,8 @@ pub fn new() -> Weak<T> {
 
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
-    /// It is up to the caller to ensure that the object is still alive when accessing it through
-    /// the pointer.
-    ///
-    /// The pointer may be [`null`] or be dangling in case the object has already been destroyed.
+    /// The pointer is valid only if there are some strong references. The pointer may be dangling
+    /// or even [`null`] otherwise.
     ///
     /// # Examples
     ///
@@ -1731,14 +1729,18 @@ pub fn into_raw(self) -> *const T {
     /// This can be used to safely get a strong reference (by calling [`upgrade`]
     /// later) or to deallocate the weak count by dropping the `Weak<T>`.
     ///
-    /// It takes ownership of one weak count. In case a [`null`] is passed, a dangling [`Weak`] is
-    /// returned.
+    /// It takes ownership of one weak count (with the exception of pointers created by [`new`],
+    /// as these don't have any corresponding weak count).
     ///
     /// # Safety
     ///
-    /// The pointer must represent one valid weak count. In other words, it must point to `T` which
-    /// is or *was* managed by an [`Rc`] and the weak count of that [`Rc`] must not have reached
-    /// 0. It is allowed for the strong count to be 0.
+    /// The pointer must have originated from the [`into_raw`] (or [`as_raw`], provided there was
+    /// a corresponding [`forget`] on the `Weak<T>`) and must still own its potential weak reference
+    /// count.
+    ///
+    /// It is allowed for the strong count to be 0 at the time of calling this, but the weak count
+    /// must be non-zero or the pointer must have originated from a dangling `Weak<T>` (one created
+    /// by [`new`]).
     ///
     /// # Examples
     ///
@@ -1763,11 +1765,13 @@ pub fn into_raw(self) -> *const T {
     /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none());
     /// ```
     ///
-    /// [`null`]: ../../std/ptr/fn.null.html
     /// [`into_raw`]: struct.Weak.html#method.into_raw
     /// [`upgrade`]: struct.Weak.html#method.upgrade
     /// [`Rc`]: struct.Rc.html
     /// [`Weak`]: struct.Weak.html
+    /// [`as_raw`]: struct.Weak.html#method.as_raw
+    /// [`new`]: struct.Weak.html#method.new
+    /// [`forget`]: ../../std/mem/fn.forget.html
     #[unstable(feature = "weak_into_raw", issue = "60728")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
         if ptr.is_null() {
index 7bf2ff13615dc70834c2bf3243ae3c94e60f913a..19b0086fa333cc1a25005ff83c99b105c55232eb 100644 (file)
@@ -1324,10 +1324,8 @@ pub fn new() -> Weak<T> {
 
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
-    /// It is up to the caller to ensure that the object is still alive when accessing it through
-    /// the pointer.
-    ///
-    /// The pointer may be [`null`] or be dangling in case the object has already been destroyed.
+    /// The pointer is valid only if there are some strong references. The pointer may be dangling
+    /// or even [`null`] otherwise.
     ///
     /// # Examples
     ///
@@ -1408,14 +1406,18 @@ pub fn into_raw(self) -> *const T {
     /// This can be used to safely get a strong reference (by calling [`upgrade`]
     /// later) or to deallocate the weak count by dropping the `Weak<T>`.
     ///
-    /// It takes ownership of one weak count. In case a [`null`] is passed, a dangling [`Weak`] is
-    /// returned.
+    /// It takes ownership of one weak count (with the exception of pointers created by [`new`],
+    /// as these don't have any corresponding weak count).
     ///
     /// # Safety
     ///
-    /// The pointer must represent one valid weak count. In other words, it must point to `T` which
-    /// is or *was* managed by an [`Arc`] and the weak count of that [`Arc`] must not have reached
-    /// 0. It is allowed for the strong count to be 0.
+    /// The pointer must have originated from the [`into_raw`] (or [`as_raw'], provided there was
+    /// a corresponding [`forget`] on the `Weak<T>`) and must still own its potential weak reference
+    /// count.
+    ///
+    /// It is allowed for the strong count to be 0 at the time of calling this, but the weak count
+    /// must be non-zero or the pointer must have originated from a dangling `Weak<T>` (one created
+    /// by [`new`]).
     ///
     /// # Examples
     ///
@@ -1440,11 +1442,13 @@ pub fn into_raw(self) -> *const T {
     /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none());
     /// ```
     ///
-    /// [`null`]: ../../std/ptr/fn.null.html
+    /// [`as_raw`]: struct.Weak.html#method.as_raw
+    /// [`new`]: struct.Weak.html#method.new
     /// [`into_raw`]: struct.Weak.html#method.into_raw
     /// [`upgrade`]: struct.Weak.html#method.upgrade
     /// [`Weak`]: struct.Weak.html
     /// [`Arc`]: struct.Arc.html
+    /// [`forget`]: ../../std/mem/fn.forget.html
     #[unstable(feature = "weak_into_raw", issue = "60728")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
         if ptr.is_null() {
index 25b7eec5b33432ab5cb5689e0cf48d202d4e8999..b2a420f3c43778cc06d992c62dbaaa89410f931a 100644 (file)
@@ -3371,8 +3371,8 @@ pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
     /// An iterator over the disjoint matches of a pattern within the given string
     /// slice.
     ///
-    /// The pattern can be any type that implements the Pattern trait. Notable
-    /// examples are `&str`, [`char`], and closures that determines the split.
+    /// The pattern can be a `&str`, [`char`], or a closure that determines if
+    /// a character matches.
     ///
     /// # Iterator behavior
     ///
index 251d49db0625389baf9260ad076b9c8a8cba2a7d..6e1aac00c7bc5401e536dcba652394b4afb6428e 100644 (file)
@@ -27,7 +27,7 @@
 //!
 //! Atomic variables are safe to share between threads (they implement [`Sync`])
 //! but they do not themselves provide the mechanism for sharing and follow the
-//! [threading model](../../../std/thread/index.html#the-threading-model) of rust.
+//! [threading model](../../../std/thread/index.html#the-threading-model) of Rust.
 //! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an
 //! atomically-reference-counted shared pointer).
 //!
index 5a940f2f80aa2a70bbd98ba455b1e9f982cd1356..58c1498faa9dedbe017a69f05f810dcb2af0a3b0 100644 (file)
@@ -1809,12 +1809,17 @@ fn report_sub_sup_conflict(
                             sub_region,
                             "...",
                         );
-                        err.note(&format!(
-                            "...so that the {}:\nexpected {}\n   found {}",
-                            sup_trace.cause.as_requirement_str(),
-                            sup_expected.content(),
-                            sup_found.content()
+                        err.span_note(sup_trace.cause.span, &format!(
+                            "...so that the {}",
+                            sup_trace.cause.as_requirement_str()
                         ));
+
+                        err.note_expected_found(
+                            &"",
+                            sup_expected,
+                            &"",
+                            sup_found
+                        );
                         err.emit();
                         return;
                     }
index c1f840ad678151ee53198ed16ec05de6c232ed2e..4b933735fc75f4eb472869de845881a0b0750c20 100644 (file)
@@ -13,12 +13,20 @@ pub(super) fn note_region_origin(&self,
         match *origin {
             infer::Subtype(ref trace) => {
                 if let Some((expected, found)) = self.values_str(&trace.values) {
-                    let expected = expected.content();
-                    let found = found.content();
-                    err.note(&format!("...so that the {}:\nexpected {}\n   found {}",
-                                      trace.cause.as_requirement_str(),
-                                      expected,
-                                      found));
+                    err.span_note(
+                        trace.cause.span,
+                        &format!(
+                            "...so that the {}",
+                            trace.cause.as_requirement_str()
+                        )
+                    );
+
+                    err.note_expected_found(
+                        &"",
+                        expected,
+                        &"",
+                        found
+                    );
                 } else {
                     // FIXME: this really should be handled at some earlier stage. Our
                     // handling of region checking when type errors are present is
index fff2f06e87b8edc3cb81c65244695cd4b7f0155a..745f7d0276d809b28df9739c6e67ef5cbbeba1e1 100644 (file)
@@ -1282,6 +1282,9 @@ fn path_append(
             if !self.empty_path {
                 write!(self, "::")?;
             }
+            if ast::Ident::from_str(&name).is_raw_guess() {
+                write!(self, "r#")?;
+            }
             write!(self, "{}", name)?;
 
             // FIXME(eddyb) this will print e.g. `{{closure}}#3`, but it
index 48bbc1307238706250e340cb9095627a2e6d8080..a05ba9c78e0d2cad0871e5603f1f28e48483b768 100644 (file)
@@ -588,14 +588,11 @@ extern "C" fn demangle_callback(input_ptr: *const c_char,
                     cursor.position() as size_t
                 }
 
-                with_codegen(tm, llmod, config.no_builtins, |cpm| {
-                    let result =
-                        llvm::LLVMRustPrintModule(cpm, llmod, out_c.as_ptr(), demangle_callback);
-                    llvm::LLVMDisposePassManager(cpm);
-                    result.into_result().map_err(|()| {
-                        let msg = format!("failed to write LLVM IR to {}", out.display());
-                        llvm_err(diag_handler, &msg)
-                    })
+                let result =
+                    llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
+                result.into_result().map_err(|()| {
+                    let msg = format!("failed to write LLVM IR to {}", out.display());
+                    llvm_err(diag_handler, &msg)
                 })?;
             }
 
index fd31e65c9d320fbe72f27cc7405c86b45f5ca5ae..5362d180d1b7858cd1c66f04f6bfcefe63f48d71 100644 (file)
@@ -1727,8 +1727,7 @@ pub fn LLVMRustWriteOutputFile(T: &'a TargetMachine,
                                    Output: *const c_char,
                                    FileType: FileType)
                                    -> LLVMRustResult;
-    pub fn LLVMRustPrintModule(PM: &PassManager<'a>,
-                               M: &'a Module,
+    pub fn LLVMRustPrintModule(M: &'a Module,
                                Output: *const c_char,
                                Demangle: extern fn(*const c_char,
                                                    size_t,
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
deleted file mode 100644 (file)
index b1e327c..0000000
+++ /dev/null
@@ -1,2156 +0,0 @@
-use rustc::hir;
-use rustc::hir::def_id::DefId;
-use rustc::hir::{AsyncGeneratorKind, GeneratorKind};
-use rustc::mir::{
-    self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
-    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
-    PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
-};
-use rustc::ty::{self, Ty};
-use rustc::traits::error_reporting::suggest_constraining_type_param;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_index::vec::Idx;
-use rustc_errors::{Applicability, DiagnosticBuilder};
-use syntax_pos::Span;
-use syntax::source_map::DesugaringKind;
-
-use super::nll::explain_borrow::BorrowExplanation;
-use super::nll::region_infer::{RegionName, RegionNameSource};
-use super::prefixes::IsPrefixOf;
-use super::WriteKind;
-use super::borrow_set::BorrowData;
-use super::MirBorrowckCtxt;
-use super::{InitializationRequiringAction, PrefixSet};
-use super::error_reporting::{IncludingDowncast, UseSpans};
-use crate::dataflow::drop_flag_effects;
-use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
-use crate::util::borrowck_errors;
-
-#[derive(Debug)]
-struct MoveSite {
-    /// Index of the "move out" that we found. The `MoveData` can
-    /// then tell us where the move occurred.
-    moi: MoveOutIndex,
-
-    /// `true` if we traversed a back edge while walking from the point
-    /// of error to the move site.
-    traversed_back_edge: bool
-}
-
-/// Which case a StorageDeadOrDrop is for.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum StorageDeadOrDrop<'tcx> {
-    LocalStorageDead,
-    BoxedStorageDead,
-    Destructor(Ty<'tcx>),
-}
-
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
-    pub(super) fn report_use_of_moved_or_uninitialized(
-        &mut self,
-        location: Location,
-        desired_action: InitializationRequiringAction,
-        (moved_place, used_place, span): (PlaceRef<'cx, 'tcx>, PlaceRef<'cx, 'tcx>, Span),
-        mpi: MovePathIndex,
-    ) {
-        debug!(
-            "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
-             moved_place={:?} used_place={:?} span={:?} mpi={:?}",
-            location, desired_action, moved_place, used_place, span, mpi
-        );
-
-        let use_spans = self.move_spans(moved_place, location)
-            .or_else(|| self.borrow_spans(span, location));
-        let span = use_spans.args_or_use();
-
-        let move_site_vec = self.get_moved_indexes(location, mpi);
-        debug!(
-            "report_use_of_moved_or_uninitialized: move_site_vec={:?}",
-            move_site_vec
-        );
-        let move_out_indices: Vec<_> = move_site_vec
-            .iter()
-            .map(|move_site| move_site.moi)
-            .collect();
-
-        if move_out_indices.is_empty() {
-            let root_place = self
-                .prefixes(used_place, PrefixSet::All)
-                .last()
-                .unwrap();
-
-            if !self.uninitialized_error_reported.insert(root_place) {
-                debug!(
-                    "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
-                    root_place
-                );
-                return;
-            }
-
-            let item_msg = match self.describe_place_with_options(used_place,
-                                                                  IncludingDowncast(true)) {
-                Some(name) => format!("`{}`", name),
-                None => "value".to_owned(),
-            };
-            let mut err = self.cannot_act_on_uninitialized_variable(
-                span,
-                desired_action.as_noun(),
-                &self.describe_place_with_options(moved_place, IncludingDowncast(true))
-                    .unwrap_or_else(|| "_".to_owned()),
-            );
-            err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
-
-            use_spans.var_span_label(
-                &mut err,
-                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
-            );
-
-            err.buffer(&mut self.errors_buffer);
-        } else {
-            if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
-                if self.prefixes(*reported_place, PrefixSet::All)
-                    .any(|p| p == used_place)
-                {
-                    debug!(
-                        "report_use_of_moved_or_uninitialized place: error suppressed \
-                         mois={:?}",
-                        move_out_indices
-                    );
-                    return;
-                }
-            }
-
-            let msg = ""; //FIXME: add "partially " or "collaterally "
-
-            let mut err = self.cannot_act_on_moved_value(
-                span,
-                desired_action.as_noun(),
-                msg,
-                self.describe_place_with_options(moved_place, IncludingDowncast(true)),
-            );
-
-            self.add_moved_or_invoked_closure_note(
-                location,
-                used_place,
-                &mut err,
-            );
-
-            let mut is_loop_move = false;
-            let is_partial_move = move_site_vec.iter().any(|move_site| {
-                let move_out = self.move_data.moves[(*move_site).moi];
-                let moved_place = &self.move_data.move_paths[move_out.path].place;
-                used_place != moved_place.as_ref()
-                    && used_place.is_prefix_of(moved_place.as_ref())
-            });
-            for move_site in &move_site_vec {
-                let move_out = self.move_data.moves[(*move_site).moi];
-                let moved_place = &self.move_data.move_paths[move_out.path].place;
-
-                let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
-                let move_span = move_spans.args_or_use();
-
-                let move_msg = if move_spans.for_closure() {
-                    " into closure"
-                } else {
-                    ""
-                };
-
-                if span == move_span {
-                    err.span_label(
-                        span,
-                        format!("value moved{} here, in previous iteration of loop", move_msg),
-                    );
-                    is_loop_move = true;
-                } else if move_site.traversed_back_edge {
-                    err.span_label(
-                        move_span,
-                        format!(
-                            "value moved{} here, in previous iteration of loop",
-                            move_msg
-                        ),
-                    );
-                } else {
-                    err.span_label(move_span, format!("value moved{} here", move_msg));
-                    move_spans.var_span_label(
-                        &mut err,
-                        format!("variable moved due to use{}", move_spans.describe()),
-                    );
-                }
-                if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
-                    let sess = self.infcx.tcx.sess;
-                    if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
-                        err.span_suggestion(
-                            move_span,
-                            "consider borrowing to avoid moving into the for loop",
-                            format!("&{}", snippet),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-
-            use_spans.var_span_label(
-                &mut err,
-                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
-            );
-
-            if !is_loop_move {
-                err.span_label(
-                    span,
-                    format!(
-                        "value {} here {}",
-                        desired_action.as_verb_in_past_tense(),
-                        if is_partial_move { "after partial move" } else { "after move" },
-                    ),
-                );
-            }
-
-            let ty = Place::ty_from(
-                used_place.base,
-                used_place.projection,
-                *self.body,
-                self.infcx.tcx
-            ).ty;
-            let needs_note = match ty.kind {
-                ty::Closure(id, _) => {
-                    let tables = self.infcx.tcx.typeck_tables_of(id);
-                    let hir_id = self.infcx.tcx.hir().as_local_hir_id(id).unwrap();
-
-                    tables.closure_kind_origins().get(hir_id).is_none()
-                }
-                _ => true,
-            };
-
-            if needs_note {
-                let mpi = self.move_data.moves[move_out_indices[0]].path;
-                let place = &self.move_data.move_paths[mpi].place;
-
-                let ty = place.ty(*self.body, self.infcx.tcx).ty;
-                let opt_name =
-                    self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
-                let note_msg = match opt_name {
-                    Some(ref name) => format!("`{}`", name),
-                    None => "value".to_owned(),
-                };
-                if let ty::Param(param_ty) = ty.kind {
-                    let tcx = self.infcx.tcx;
-                    let generics = tcx.generics_of(self.mir_def_id);
-                    let param = generics.type_param(&param_ty, tcx);
-                    let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
-                    suggest_constraining_type_param(
-                        generics,
-                        &mut err,
-                        &param.name.as_str(),
-                        "Copy",
-                        tcx.sess.source_map(),
-                        span,
-                    );
-                }
-                let span = if let Some(local) = place.as_local() {
-                    let decl = &self.body.local_decls[local];
-                    Some(decl.source_info.span)
-                } else {
-                    None
-                };
-                self.note_type_does_not_implement_copy(
-                    &mut err,
-                    &note_msg,
-                    ty,
-                    span,
-                );
-            }
-
-            if let Some((_, mut old_err)) = self.move_error_reported
-                .insert(move_out_indices, (used_place, err))
-            {
-                // Cancel the old error so it doesn't ICE.
-                old_err.cancel();
-            }
-        }
-    }
-
-    pub(super) fn report_move_out_while_borrowed(
-        &mut self,
-        location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        borrow: &BorrowData<'tcx>,
-    ) {
-        debug!(
-            "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
-            location, place, span, borrow
-        );
-        let value_msg = match self.describe_place(place.as_ref()) {
-            Some(name) => format!("`{}`", name),
-            None => "value".to_owned(),
-        };
-        let borrow_msg = match self.describe_place(borrow.borrowed_place.as_ref()) {
-            Some(name) => format!("`{}`", name),
-            None => "value".to_owned(),
-        };
-
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.args_or_use();
-
-        let move_spans = self.move_spans(place.as_ref(), location);
-        let span = move_spans.args_or_use();
-
-        let mut err = self.cannot_move_when_borrowed(
-            span,
-            &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
-        );
-        err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
-        err.span_label(span, format!("move out of {} occurs here", value_msg));
-
-        borrow_spans.var_span_label(
-            &mut err,
-            format!("borrow occurs due to use{}", borrow_spans.describe())
-        );
-
-        move_spans.var_span_label(
-            &mut err,
-            format!("move occurs due to use{}", move_spans.describe())
-        );
-
-        self.explain_why_borrow_contains_point(
-            location,
-            borrow,
-            None,
-        ).add_explanation_to_diagnostic(
-            self.infcx.tcx,
-            &self.body,
-            &self.local_names,
-            &mut err,
-            "",
-            Some(borrow_span),
-        );
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    pub(super) fn report_use_while_mutably_borrowed(
-        &mut self,
-        location: Location,
-        (place, _span): (&Place<'tcx>, Span),
-        borrow: &BorrowData<'tcx>,
-    ) -> DiagnosticBuilder<'cx> {
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.args_or_use();
-
-        // Conflicting borrows are reported separately, so only check for move
-        // captures.
-        let use_spans = self.move_spans(place.as_ref(), location);
-        let span = use_spans.var_or_use();
-
-        let mut err = self.cannot_use_when_mutably_borrowed(
-            span,
-            &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
-            borrow_span,
-            &self.describe_place(borrow.borrowed_place.as_ref())
-                .unwrap_or_else(|| "_".to_owned()),
-        );
-
-        borrow_spans.var_span_label(&mut err, {
-            let place = &borrow.borrowed_place;
-            let desc_place =
-                self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned());
-
-            format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
-        });
-
-        self.explain_why_borrow_contains_point(location, borrow, None)
-            .add_explanation_to_diagnostic(
-                self.infcx.tcx,
-                &self.body,
-                &self.local_names,
-                &mut err,
-                "",
-                None,
-            );
-        err
-    }
-
-    pub(super) fn report_conflicting_borrow(
-        &mut self,
-        location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        gen_borrow_kind: BorrowKind,
-        issued_borrow: &BorrowData<'tcx>,
-    ) -> DiagnosticBuilder<'cx> {
-        let issued_spans = self.retrieve_borrow_spans(issued_borrow);
-        let issued_span = issued_spans.args_or_use();
-
-        let borrow_spans = self.borrow_spans(span, location);
-        let span = borrow_spans.args_or_use();
-
-        let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
-            "generator"
-        } else {
-            "closure"
-        };
-
-        let (desc_place, msg_place, msg_borrow, union_type_name) =
-            self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
-
-        let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
-        let second_borrow_desc = if explanation.is_explained() {
-            "second "
-        } else {
-            ""
-        };
-
-        // FIXME: supply non-"" `opt_via` when appropriate
-        let first_borrow_desc;
-        let mut err = match (
-            gen_borrow_kind,
-            issued_borrow.kind,
-        ) {
-            (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
-                first_borrow_desc = "mutable ";
-                self.cannot_reborrow_already_borrowed(
-                    span,
-                    &desc_place,
-                    &msg_place,
-                    "immutable",
-                    issued_span,
-                    "it",
-                    "mutable",
-                    &msg_borrow,
-                    None,
-                )
-            }
-            (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
-                first_borrow_desc = "immutable ";
-                self.cannot_reborrow_already_borrowed(
-                    span,
-                    &desc_place,
-                    &msg_place,
-                    "mutable",
-                    issued_span,
-                    "it",
-                    "immutable",
-                    &msg_borrow,
-                    None,
-                )
-            }
-
-            (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
-                first_borrow_desc = "first ";
-                self.cannot_mutably_borrow_multiply(
-                    span,
-                    &desc_place,
-                    &msg_place,
-                    issued_span,
-                    &msg_borrow,
-                    None,
-                )
-            }
-
-            (BorrowKind::Unique, BorrowKind::Unique) => {
-                first_borrow_desc = "first ";
-                self.cannot_uniquely_borrow_by_two_closures(
-                    span,
-                    &desc_place,
-                    issued_span,
-                    None,
-                )
-            }
-
-            (BorrowKind::Mut { .. }, BorrowKind::Shallow)
-            | (BorrowKind::Unique, BorrowKind::Shallow) => {
-                if let Some(immutable_section_description) = self.classify_immutable_section(
-                    &issued_borrow.assigned_place,
-                ) {
-                    let mut err = self.cannot_mutate_in_immutable_section(
-                        span,
-                        issued_span,
-                        &desc_place,
-                        immutable_section_description,
-                        "mutably borrow",
-                    );
-                    borrow_spans.var_span_label(
-                        &mut err,
-                        format!(
-                            "borrow occurs due to use of `{}`{}",
-                            desc_place,
-                            borrow_spans.describe(),
-                        ),
-                    );
-
-                    return err;
-                } else {
-                    first_borrow_desc = "immutable ";
-                    self.cannot_reborrow_already_borrowed(
-                        span,
-                        &desc_place,
-                        &msg_place,
-                        "mutable",
-                        issued_span,
-                        "it",
-                        "immutable",
-                        &msg_borrow,
-                        None,
-                    )
-                }
-            }
-
-            (BorrowKind::Unique, _) => {
-                first_borrow_desc = "first ";
-                self.cannot_uniquely_borrow_by_one_closure(
-                    span,
-                    container_name,
-                    &desc_place,
-                    "",
-                    issued_span,
-                    "it",
-                    "",
-                    None,
-                )
-            },
-
-            (BorrowKind::Shared, BorrowKind::Unique) => {
-                first_borrow_desc = "first ";
-                self.cannot_reborrow_already_uniquely_borrowed(
-                    span,
-                    container_name,
-                    &desc_place,
-                    "",
-                    "immutable",
-                    issued_span,
-                    "",
-                    None,
-                    second_borrow_desc,
-                )
-            }
-
-            (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
-                first_borrow_desc = "first ";
-                self.cannot_reborrow_already_uniquely_borrowed(
-                    span,
-                    container_name,
-                    &desc_place,
-                    "",
-                    "mutable",
-                    issued_span,
-                    "",
-                    None,
-                    second_borrow_desc,
-                )
-            }
-
-            (BorrowKind::Shared, BorrowKind::Shared)
-            | (BorrowKind::Shared, BorrowKind::Shallow)
-            | (BorrowKind::Shallow, BorrowKind::Mut { .. })
-            | (BorrowKind::Shallow, BorrowKind::Unique)
-            | (BorrowKind::Shallow, BorrowKind::Shared)
-            | (BorrowKind::Shallow, BorrowKind::Shallow) => unreachable!(),
-        };
-
-        if issued_spans == borrow_spans {
-            borrow_spans.var_span_label(
-                &mut err,
-                format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()),
-            );
-        } else {
-            let borrow_place = &issued_borrow.borrowed_place;
-            let borrow_place_desc = self.describe_place(borrow_place.as_ref())
-                                        .unwrap_or_else(|| "_".to_owned());
-            issued_spans.var_span_label(
-                &mut err,
-                format!(
-                    "first borrow occurs due to use of `{}`{}",
-                    borrow_place_desc,
-                    issued_spans.describe(),
-                ),
-            );
-
-            borrow_spans.var_span_label(
-                &mut err,
-                format!(
-                    "second borrow occurs due to use of `{}`{}",
-                    desc_place,
-                    borrow_spans.describe(),
-                ),
-            );
-        }
-
-        if union_type_name != "" {
-            err.note(&format!(
-                "`{}` is a field of the union `{}`, so it overlaps the field `{}`",
-                msg_place, union_type_name, msg_borrow,
-            ));
-        }
-
-        explanation.add_explanation_to_diagnostic(
-            self.infcx.tcx,
-            &self.body,
-            &self.local_names,
-            &mut err,
-            first_borrow_desc,
-            None,
-        );
-
-        err
-    }
-
-    /// Returns the description of the root place for a conflicting borrow and the full
-    /// descriptions of the places that caused the conflict.
-    ///
-    /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
-    /// attempted while a shared borrow is live, then this function will return:
-    ///
-    ///     ("x", "", "")
-    ///
-    /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
-    /// a shared borrow of another field `x.y`, then this function will return:
-    ///
-    ///     ("x", "x.z", "x.y")
-    ///
-    /// In the more complex union case, where the union is a field of a struct, then if a mutable
-    /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
-    /// another field `x.u.y`, then this function will return:
-    ///
-    ///     ("x.u", "x.u.z", "x.u.y")
-    ///
-    /// This is used when creating error messages like below:
-    ///
-    /// >  cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
-    /// >  mutable (via `a.u.s.b`) [E0502]
-    pub(super) fn describe_place_for_conflicting_borrow(
-        &self,
-        first_borrowed_place: &Place<'tcx>,
-        second_borrowed_place: &Place<'tcx>,
-    ) -> (String, String, String, String) {
-        // Define a small closure that we can use to check if the type of a place
-        // is a union.
-        let union_ty = |place_base, place_projection| {
-            let ty = Place::ty_from(
-                place_base,
-                place_projection,
-                *self.body,
-                self.infcx.tcx
-            ).ty;
-            ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
-        };
-        let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned());
-
-        // Start with an empty tuple, so we can use the functions on `Option` to reduce some
-        // code duplication (particularly around returning an empty description in the failure
-        // case).
-        Some(())
-            .filter(|_| {
-                // If we have a conflicting borrow of the same place, then we don't want to add
-                // an extraneous "via x.y" to our diagnostics, so filter out this case.
-                first_borrowed_place != second_borrowed_place
-            })
-            .and_then(|_| {
-                // We're going to want to traverse the first borrowed place to see if we can find
-                // field access to a union. If we find that, then we will keep the place of the
-                // union being accessed and the field that was being accessed so we can check the
-                // second borrowed place for the same union and a access to a different field.
-                let Place {
-                    base,
-                    projection,
-                } = first_borrowed_place;
-
-                let mut cursor = projection.as_ref();
-                while let [proj_base @ .., elem] = cursor {
-                    cursor = proj_base;
-
-                    match elem {
-                        ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
-                            return Some((PlaceRef {
-                                base: base,
-                                projection: proj_base,
-                            }, field));
-                        },
-                        _ => {},
-                    }
-                }
-                None
-            })
-            .and_then(|(target_base, target_field)| {
-                // With the place of a union and a field access into it, we traverse the second
-                // borrowed place and look for a access to a different field of the same union.
-                let Place {
-                    base,
-                    projection,
-                } = second_borrowed_place;
-
-                let mut cursor = projection.as_ref();
-                while let [proj_base @ .., elem] = cursor {
-                    cursor = proj_base;
-
-                    if let ProjectionElem::Field(field, _) = elem {
-                        if let Some(union_ty) = union_ty(base, proj_base) {
-                            if field != target_field
-                                && base == target_base.base
-                                && proj_base == target_base.projection {
-                                // FIXME when we avoid clone reuse describe_place closure
-                                let describe_base_place =  self.describe_place(PlaceRef {
-                                    base: base,
-                                    projection: proj_base,
-                                }).unwrap_or_else(|| "_".to_owned());
-
-                                return Some((
-                                    describe_base_place,
-                                    describe_place(first_borrowed_place.as_ref()),
-                                    describe_place(second_borrowed_place.as_ref()),
-                                    union_ty.to_string(),
-                                ));
-                            }
-                        }
-                    }
-                }
-                None
-            })
-            .unwrap_or_else(|| {
-                // If we didn't find a field access into a union, or both places match, then
-                // only return the description of the first place.
-                (
-                    describe_place(first_borrowed_place.as_ref()),
-                    "".to_string(),
-                    "".to_string(),
-                    "".to_string(),
-                )
-            })
-    }
-
-    /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
-    ///
-    /// This means that some data referenced by `borrow` needs to live
-    /// past the point where the StorageDeadOrDrop of `place` occurs.
-    /// This is usually interpreted as meaning that `place` has too
-    /// short a lifetime. (But sometimes it is more useful to report
-    /// it as a more direct conflict between the execution of a
-    /// `Drop::drop` with an aliasing borrow.)
-    pub(super) fn report_borrowed_value_does_not_live_long_enough(
-        &mut self,
-        location: Location,
-        borrow: &BorrowData<'tcx>,
-        place_span: (&Place<'tcx>, Span),
-        kind: Option<WriteKind>,
-    ) {
-        debug!(
-            "report_borrowed_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, borrow, place_span, kind
-        );
-
-        let drop_span = place_span.1;
-        let root_place = self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All)
-            .last()
-            .unwrap();
-
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.var_or_use();
-
-        assert!(root_place.projection.is_empty());
-        let proper_span = match root_place.base {
-            PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
-            _ => drop_span,
-        };
-
-        let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
-
-        if self.access_place_error_reported
-            .contains(&(Place {
-                base: root_place.base.clone(),
-                projection: root_place_projection,
-            }, borrow_span))
-        {
-            debug!(
-                "suppressing access_place error when borrow doesn't live long enough for {:?}",
-                borrow_span
-            );
-            return;
-        }
-
-        self.access_place_error_reported
-            .insert((Place {
-                base: root_place.base.clone(),
-                projection: root_place_projection,
-            }, borrow_span));
-
-        if let PlaceBase::Local(local) = borrow.borrowed_place.base {
-            if self.body.local_decls[local].is_ref_to_thread_local() {
-                let err = self.report_thread_local_value_does_not_live_long_enough(
-                    drop_span,
-                    borrow_span,
-                );
-                err.buffer(&mut self.errors_buffer);
-                return;
-            }
-        };
-
-        if let StorageDeadOrDrop::Destructor(dropped_ty) =
-            self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
-        {
-            // If a borrow of path `B` conflicts with drop of `D` (and
-            // we're not in the uninteresting case where `B` is a
-            // prefix of `D`), then report this as a more interesting
-            // destructor conflict.
-            if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
-                self.report_borrow_conflicts_with_destructor(
-                    location, borrow, place_span, kind, dropped_ty,
-                );
-                return;
-            }
-        }
-
-        let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
-
-        let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
-        let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
-
-        debug!(
-            "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
-            place_desc,
-            explanation
-        );
-        let err = match (place_desc, explanation) {
-            // If the outlives constraint comes from inside the closure,
-            // for example:
-            //
-            // let x = 0;
-            // let y = &x;
-            // Box::new(|| y) as Box<Fn() -> &'static i32>
-            //
-            // then just use the normal error. The closure isn't escaping
-            // and `move` will not help here.
-            (
-                Some(ref name),
-                BorrowExplanation::MustBeValidFor {
-                    category: category @ ConstraintCategory::Return,
-                    from_closure: false,
-                    ref region_name,
-                    span,
-                    ..
-                },
-            )
-            | (
-                Some(ref name),
-                BorrowExplanation::MustBeValidFor {
-                    category: category @ ConstraintCategory::CallArgument,
-                    from_closure: false,
-                    ref region_name,
-                    span,
-                    ..
-                },
-            ) if borrow_spans.for_closure() => self.report_escaping_closure_capture(
-                borrow_spans,
-                borrow_span,
-                region_name,
-                category,
-                span,
-                &format!("`{}`", name),
-            ),
-            (
-                Some(ref name),
-                BorrowExplanation::MustBeValidFor {
-                    category: category @ ConstraintCategory::OpaqueType,
-                    from_closure: false,
-                    ref region_name,
-                    span,
-                    ..
-                },
-
-            ) if borrow_spans.for_generator() => self.report_escaping_closure_capture(
-                borrow_spans,
-                borrow_span,
-                region_name,
-                category,
-                span,
-                &format!("`{}`", name),
-            ),
-            (
-                ref name,
-                BorrowExplanation::MustBeValidFor {
-                    category: ConstraintCategory::Assignment,
-                    from_closure: false,
-                    region_name: RegionName {
-                        source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
-                        ..
-                    },
-                    span,
-                    ..
-                },
-            ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
-            (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
-                location,
-                &name,
-                &borrow,
-                drop_span,
-                borrow_spans,
-                explanation,
-            ),
-            (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
-                location,
-                &borrow,
-                drop_span,
-                borrow_spans,
-                proper_span,
-                explanation,
-            ),
-        };
-
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    fn report_local_value_does_not_live_long_enough(
-        &mut self,
-        location: Location,
-        name: &str,
-        borrow: &BorrowData<'tcx>,
-        drop_span: Span,
-        borrow_spans: UseSpans,
-        explanation: BorrowExplanation,
-    ) -> DiagnosticBuilder<'cx> {
-        debug!(
-            "report_local_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, name, borrow, drop_span, borrow_spans
-        );
-
-        let borrow_span = borrow_spans.var_or_use();
-        if let BorrowExplanation::MustBeValidFor {
-            category,
-            span,
-            ref opt_place_desc,
-            from_closure: false,
-            ..
-        } = explanation {
-            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
-                borrow,
-                borrow_span,
-                span,
-                category,
-                opt_place_desc.as_ref(),
-            ) {
-                return diag;
-            }
-        }
-
-        let mut err = self.path_does_not_live_long_enough(
-            borrow_span,
-            &format!("`{}`", name),
-        );
-
-        if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
-            let region_name = annotation.emit(self, &mut err);
-
-            err.span_label(
-                borrow_span,
-                format!("`{}` would have to be valid for `{}`...", name, region_name),
-            );
-
-            if let Some(fn_hir_id) = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id) {
-                err.span_label(
-                    drop_span,
-                    format!(
-                        "...but `{}` will be dropped here, when the function `{}` returns",
-                        name,
-                        self.infcx.tcx.hir().name(fn_hir_id),
-                    ),
-                );
-
-                err.note(
-                    "functions cannot return a borrow to data owned within the function's scope, \
-                     functions can only return borrows to data passed as arguments",
-                );
-                err.note(
-                    "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
-                     references-and-borrowing.html#dangling-references>",
-                );
-            } else {
-                err.span_label(
-                    drop_span,
-                    format!("...but `{}` dropped here while still borrowed", name),
-                );
-            }
-
-            if let BorrowExplanation::MustBeValidFor { .. } = explanation {
-            } else {
-                explanation.add_explanation_to_diagnostic(
-                    self.infcx.tcx,
-                    &self.body,
-                    &self.local_names,
-                    &mut err,
-                    "",
-                    None,
-                );
-            }
-        } else {
-            err.span_label(borrow_span, "borrowed value does not live long enough");
-            err.span_label(
-                drop_span,
-                format!("`{}` dropped here while still borrowed", name),
-            );
-
-            let within = if borrow_spans.for_generator() {
-                " by generator"
-            } else {
-                ""
-            };
-
-            borrow_spans.args_span_label(
-                &mut err,
-                format!("value captured here{}", within),
-            );
-
-            explanation.add_explanation_to_diagnostic(
-                self.infcx.tcx, &self.body, &self.local_names, &mut err, "", None);
-        }
-
-        err
-    }
-
-    fn report_borrow_conflicts_with_destructor(
-        &mut self,
-        location: Location,
-        borrow: &BorrowData<'tcx>,
-        (place, drop_span): (&Place<'tcx>, Span),
-        kind: Option<WriteKind>,
-        dropped_ty: Ty<'tcx>,
-    ) {
-        debug!(
-            "report_borrow_conflicts_with_destructor(\
-             {:?}, {:?}, ({:?}, {:?}), {:?}\
-             )",
-            location, borrow, place, drop_span, kind,
-        );
-
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.var_or_use();
-
-        let mut err = self.cannot_borrow_across_destructor(borrow_span);
-
-        let what_was_dropped = match self.describe_place(place.as_ref()) {
-            Some(name) => format!("`{}`", name),
-            None => String::from("temporary value"),
-        };
-
-        let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
-            Some(borrowed) => format!(
-                "here, drop of {D} needs exclusive access to `{B}`, \
-                 because the type `{T}` implements the `Drop` trait",
-                D = what_was_dropped,
-                T = dropped_ty,
-                B = borrowed
-            ),
-            None => format!(
-                "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
-                D = what_was_dropped,
-                T = dropped_ty
-            ),
-        };
-        err.span_label(drop_span, label);
-
-        // Only give this note and suggestion if they could be relevant.
-        let explanation =
-            self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
-        match explanation {
-            BorrowExplanation::UsedLater { .. }
-            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
-                err.note("consider using a `let` binding to create a longer lived value");
-            }
-            _ => {}
-        }
-
-        explanation.add_explanation_to_diagnostic(
-            self.infcx.tcx,
-            &self.body,
-            &self.local_names,
-            &mut err,
-            "",
-            None,
-        );
-
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    fn report_thread_local_value_does_not_live_long_enough(
-        &mut self,
-        drop_span: Span,
-        borrow_span: Span,
-    ) -> DiagnosticBuilder<'cx> {
-        debug!(
-            "report_thread_local_value_does_not_live_long_enough(\
-             {:?}, {:?}\
-             )",
-            drop_span, borrow_span
-        );
-
-        let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
-
-        err.span_label(
-            borrow_span,
-            "thread-local variables cannot be borrowed beyond the end of the function",
-        );
-        err.span_label(drop_span, "end of enclosing function is here");
-
-        err
-    }
-
-    fn report_temporary_value_does_not_live_long_enough(
-        &mut self,
-        location: Location,
-        borrow: &BorrowData<'tcx>,
-        drop_span: Span,
-        borrow_spans: UseSpans,
-        proper_span: Span,
-        explanation: BorrowExplanation,
-    ) -> DiagnosticBuilder<'cx> {
-        debug!(
-            "report_temporary_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, borrow, drop_span, proper_span
-        );
-
-        if let BorrowExplanation::MustBeValidFor {
-            category,
-            span,
-            from_closure: false,
-            ..
-        } = explanation {
-            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
-                borrow,
-                proper_span,
-                span,
-                category,
-                None,
-            ) {
-                return diag;
-            }
-        }
-
-        let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
-        err.span_label(
-            proper_span,
-            "creates a temporary which is freed while still in use",
-        );
-        err.span_label(
-            drop_span,
-            "temporary value is freed at the end of this statement",
-        );
-
-        match explanation {
-            BorrowExplanation::UsedLater(..)
-            | BorrowExplanation::UsedLaterInLoop(..)
-            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
-                // Only give this note and suggestion if it could be relevant.
-                err.note("consider using a `let` binding to create a longer lived value");
-            }
-            _ => {}
-        }
-        explanation.add_explanation_to_diagnostic(
-            self.infcx.tcx,
-            &self.body,
-            &self.local_names,
-            &mut err,
-            "",
-            None,
-        );
-
-        let within = if borrow_spans.for_generator() {
-            " by generator"
-        } else {
-            ""
-        };
-
-        borrow_spans.args_span_label(
-            &mut err,
-            format!("value captured here{}", within),
-        );
-
-        err
-    }
-
-    fn try_report_cannot_return_reference_to_local(
-        &self,
-        borrow: &BorrowData<'tcx>,
-        borrow_span: Span,
-        return_span: Span,
-        category: ConstraintCategory,
-        opt_place_desc: Option<&String>,
-    ) -> Option<DiagnosticBuilder<'cx>> {
-        let return_kind = match category {
-            ConstraintCategory::Return => "return",
-            ConstraintCategory::Yield => "yield",
-            _ => return None,
-        };
-
-        // FIXME use a better heuristic than Spans
-        let reference_desc
-            = if return_span == self.body.source_info(borrow.reserve_location).span {
-                "reference to"
-            } else {
-                "value referencing"
-            };
-
-        let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
-            let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
-                match self.body.local_kind(local) {
-                    LocalKind::ReturnPointer
-                    | LocalKind::Temp => bug!("temporary or return pointer with a name"),
-                    LocalKind::Var => "local variable ",
-                    LocalKind::Arg
-                    if !self.upvars.is_empty()
-                        && local == Local::new(1) => {
-                        "variable captured by `move` "
-                    }
-                    LocalKind::Arg => {
-                        "function parameter "
-                    }
-                }
-            } else {
-                "local data "
-            };
-            (
-                format!("{}`{}`", local_kind, place_desc),
-                format!("`{}` is borrowed here", place_desc),
-            )
-        } else {
-            let root_place = self.prefixes(borrow.borrowed_place.as_ref(),
-                                           PrefixSet::All)
-                .last()
-                .unwrap();
-            let local = if let PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [],
-            } = root_place {
-                local
-            } else {
-                bug!("try_report_cannot_return_reference_to_local: not a local")
-            };
-            match self.body.local_kind(*local) {
-                LocalKind::ReturnPointer | LocalKind::Temp => (
-                    "temporary value".to_string(),
-                    "temporary value created here".to_string(),
-                ),
-                LocalKind::Arg => (
-                    "function parameter".to_string(),
-                    "function parameter borrowed here".to_string(),
-                ),
-                LocalKind::Var => (
-                    "local binding".to_string(),
-                    "local binding introduced here".to_string(),
-                ),
-            }
-        };
-
-        let mut err = self.cannot_return_reference_to_local(
-            return_span,
-            return_kind,
-            reference_desc,
-            &place_desc,
-        );
-
-        if return_span != borrow_span {
-            err.span_label(borrow_span, note);
-        }
-
-        Some(err)
-    }
-
-    fn report_escaping_closure_capture(
-        &mut self,
-        use_span: UseSpans,
-        var_span: Span,
-        fr_name: &RegionName,
-        category: ConstraintCategory,
-        constraint_span: Span,
-        captured_var: &str,
-    ) -> DiagnosticBuilder<'cx> {
-        let tcx = self.infcx.tcx;
-        let args_span = use_span.args_or_use();
-        let mut err = self.cannot_capture_in_long_lived_closure(
-            args_span,
-            captured_var,
-            var_span,
-        );
-
-        let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
-            Ok(mut string) => {
-                if string.starts_with("async ") {
-                    string.insert_str(6, "move ");
-                } else if string.starts_with("async|") {
-                    string.insert_str(5, " move");
-                } else {
-                    string.insert_str(0, "move ");
-                };
-                string
-            },
-            Err(_) => "move |<args>| <body>".to_string()
-        };
-        let kind = match use_span.generator_kind() {
-            Some(generator_kind) => match generator_kind {
-                GeneratorKind::Async(async_kind) => match async_kind {
-                    AsyncGeneratorKind::Block => "async block",
-                    AsyncGeneratorKind::Closure => "async closure",
-                    _ => bug!("async block/closure expected, but async funtion found."),
-                },
-                GeneratorKind::Gen => "generator",
-            }
-            None => "closure",
-        };
-        err.span_suggestion(
-            args_span,
-            &format!(
-                "to force the {} to take ownership of {} (and any \
-                 other referenced variables), use the `move` keyword",
-                 kind,
-                 captured_var
-            ),
-            suggestion,
-            Applicability::MachineApplicable,
-        );
-
-        let msg = match category {
-            ConstraintCategory::Return => "closure is returned here".to_string(),
-            ConstraintCategory::OpaqueType => "generator is returned here".to_string(),
-            ConstraintCategory::CallArgument => {
-                fr_name.highlight_region_name(&mut err);
-                format!("function requires argument type to outlive `{}`", fr_name)
-            }
-            _ => bug!("report_escaping_closure_capture called with unexpected constraint \
-                       category: `{:?}`", category),
-        };
-        err.span_note(constraint_span, &msg);
-        err
-    }
-
-    fn report_escaping_data(
-        &mut self,
-        borrow_span: Span,
-        name: &Option<String>,
-        upvar_span: Span,
-        upvar_name: &str,
-        escape_span: Span,
-    ) -> DiagnosticBuilder<'cx> {
-        let tcx = self.infcx.tcx;
-
-        let escapes_from = if tcx.is_closure(self.mir_def_id) {
-            let tables = tcx.typeck_tables_of(self.mir_def_id);
-            let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index);
-            match tables.node_type(mir_hir_id).kind {
-                ty::Closure(..) => "closure",
-                ty::Generator(..) => "generator",
-                _ => bug!("Closure body doesn't have a closure or generator type"),
-            }
-        } else {
-            "function"
-        };
-
-        let mut err = borrowck_errors::borrowed_data_escapes_closure(
-            tcx,
-            escape_span,
-            escapes_from,
-        );
-
-        err.span_label(
-            upvar_span,
-            format!(
-                "`{}` is declared here, outside of the {} body",
-                upvar_name, escapes_from
-            ),
-        );
-
-        err.span_label(
-            borrow_span,
-            format!(
-                "borrow is only valid in the {} body",
-                escapes_from
-            ),
-        );
-
-        if let Some(name) = name {
-            err.span_label(
-                escape_span,
-                format!("reference to `{}` escapes the {} body here", name, escapes_from),
-            );
-        } else {
-            err.span_label(
-                escape_span,
-                format!("reference escapes the {} body here", escapes_from),
-            );
-        }
-
-        err
-    }
-
-    fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
-        let mut stack = Vec::new();
-        stack.extend(self.body.predecessor_locations(location).map(|predecessor| {
-            let is_back_edge = location.dominates(predecessor, &self.dominators);
-            (predecessor, is_back_edge)
-        }));
-
-        let mut visited = FxHashSet::default();
-        let mut result = vec![];
-
-        'dfs: while let Some((location, is_back_edge)) = stack.pop() {
-            debug!(
-                "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
-                location, is_back_edge
-            );
-
-            if !visited.insert(location) {
-                continue;
-            }
-
-            // check for moves
-            let stmt_kind = self.body[location.block]
-                .statements
-                .get(location.statement_index)
-                .map(|s| &s.kind);
-            if let Some(StatementKind::StorageDead(..)) = stmt_kind {
-                // this analysis only tries to find moves explicitly
-                // written by the user, so we ignore the move-outs
-                // created by `StorageDead` and at the beginning
-                // of a function.
-            } else {
-                // If we are found a use of a.b.c which was in error, then we want to look for
-                // moves not only of a.b.c but also a.b and a.
-                //
-                // Note that the moves data already includes "parent" paths, so we don't have to
-                // worry about the other case: that is, if there is a move of a.b.c, it is already
-                // marked as a move of a.b and a as well, so we will generate the correct errors
-                // there.
-                let mut mpis = vec![mpi];
-                let move_paths = &self.move_data.move_paths;
-                mpis.extend(move_paths[mpi].parents(move_paths));
-
-                for moi in &self.move_data.loc_map[location] {
-                    debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
-                    if mpis.contains(&self.move_data.moves[*moi].path) {
-                        debug!("report_use_of_moved_or_uninitialized: found");
-                        result.push(MoveSite {
-                            moi: *moi,
-                            traversed_back_edge: is_back_edge,
-                        });
-
-                        // Strictly speaking, we could continue our DFS here. There may be
-                        // other moves that can reach the point of error. But it is kind of
-                        // confusing to highlight them.
-                        //
-                        // Example:
-                        //
-                        // ```
-                        // let a = vec![];
-                        // let b = a;
-                        // let c = a;
-                        // drop(a); // <-- current point of error
-                        // ```
-                        //
-                        // Because we stop the DFS here, we only highlight `let c = a`,
-                        // and not `let b = a`. We will of course also report an error at
-                        // `let c = a` which highlights `let b = a` as the move.
-                        continue 'dfs;
-                    }
-                }
-            }
-
-            // check for inits
-            let mut any_match = false;
-            drop_flag_effects::for_location_inits(
-                self.infcx.tcx,
-                &self.body,
-                self.move_data,
-                location,
-                |m| {
-                    if m == mpi {
-                        any_match = true;
-                    }
-                },
-            );
-            if any_match {
-                continue 'dfs;
-            }
-
-            stack.extend(self.body.predecessor_locations(location).map(|predecessor| {
-                let back_edge = location.dominates(predecessor, &self.dominators);
-                (predecessor, is_back_edge || back_edge)
-            }));
-        }
-
-        result
-    }
-
-    pub(super) fn report_illegal_mutation_of_borrowed(
-        &mut self,
-        location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        loan: &BorrowData<'tcx>,
-    ) {
-        let loan_spans = self.retrieve_borrow_spans(loan);
-        let loan_span = loan_spans.args_or_use();
-
-        if loan.kind == BorrowKind::Shallow {
-            if let Some(section) = self.classify_immutable_section(&loan.assigned_place) {
-                let mut err = self.cannot_mutate_in_immutable_section(
-                    span,
-                    loan_span,
-                    &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
-                    section,
-                    "assign",
-                );
-                loan_spans.var_span_label(
-                    &mut err,
-                    format!("borrow occurs due to use{}", loan_spans.describe()),
-                );
-
-                err.buffer(&mut self.errors_buffer);
-
-                return;
-            }
-        }
-
-        let mut err = self.cannot_assign_to_borrowed(
-            span,
-            loan_span,
-            &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
-        );
-
-        loan_spans.var_span_label(
-            &mut err,
-            format!("borrow occurs due to use{}", loan_spans.describe()),
-        );
-
-        self.explain_why_borrow_contains_point(location, loan, None)
-            .add_explanation_to_diagnostic(
-                self.infcx.tcx,
-                &self.body,
-                &self.local_names,
-                &mut err,
-                "",
-                None,
-            );
-
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    /// Reports an illegal reassignment; for example, an assignment to
-    /// (part of) a non-`mut` local that occurs potentially after that
-    /// local has already been initialized. `place` is the path being
-    /// assigned; `err_place` is a place providing a reason why
-    /// `place` is not mutable (e.g., the non-`mut` local `x` in an
-    /// assignment to `x.f`).
-    pub(super) fn report_illegal_reassignment(
-        &mut self,
-        _location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        assigned_span: Span,
-        err_place: &Place<'tcx>,
-    ) {
-        let (from_arg, local_decl, local_name) = match err_place.as_local() {
-            Some(local) => (
-                self.body.local_kind(local) == LocalKind::Arg,
-                Some(&self.body.local_decls[local]),
-                self.local_names[local],
-            ),
-            None => (false, None, None),
-        };
-
-        // If root local is initialized immediately (everything apart from let
-        // PATTERN;) then make the error refer to that local, rather than the
-        // place being assigned later.
-        let (place_description, assigned_span) = match local_decl {
-            Some(LocalDecl {
-                local_info: LocalInfo::User(ClearCrossCrate::Clear),
-                ..
-            })
-            | Some(LocalDecl {
-                local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                    opt_match_place: None,
-                    ..
-                }))),
-                ..
-            })
-            | Some(LocalDecl {
-                local_info: LocalInfo::StaticRef { .. },
-                ..
-            })
-            | Some(LocalDecl {
-                local_info: LocalInfo::Other,
-                ..
-            })
-            | None => (self.describe_place(place.as_ref()), assigned_span),
-            Some(decl) => (self.describe_place(err_place.as_ref()), decl.source_info.span),
-        };
-
-        let mut err = self.cannot_reassign_immutable(
-            span,
-            place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
-            from_arg,
-        );
-        let msg = if from_arg {
-            "cannot assign to immutable argument"
-        } else {
-            "cannot assign twice to immutable variable"
-        };
-        if span != assigned_span {
-            if !from_arg {
-                let value_msg = match place_description {
-                    Some(name) => format!("`{}`", name),
-                    None => "value".to_owned(),
-                };
-                err.span_label(assigned_span, format!("first assignment to {}", value_msg));
-            }
-        }
-        if let Some(decl) = local_decl {
-            if let Some(name) = local_name {
-                if decl.can_be_made_mutable() {
-                    err.span_suggestion(
-                        decl.source_info.span,
-                        "make this binding mutable",
-                        format!("mut {}", name),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-        }
-        err.span_label(span, msg);
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
-        let tcx = self.infcx.tcx;
-        match place.projection {
-            [] => {
-                StorageDeadOrDrop::LocalStorageDead
-            }
-            [proj_base @ .., elem] => {
-                // FIXME(spastorino) make this iterate
-                let base_access = self.classify_drop_access_kind(PlaceRef {
-                    base: place.base,
-                    projection: proj_base,
-                });
-                match elem {
-                    ProjectionElem::Deref => match base_access {
-                        StorageDeadOrDrop::LocalStorageDead
-                        | StorageDeadOrDrop::BoxedStorageDead => {
-                            assert!(
-                                Place::ty_from(
-                                    &place.base,
-                                    proj_base,
-                                    *self.body,
-                                    tcx
-                                ).ty.is_box(),
-                                "Drop of value behind a reference or raw pointer"
-                            );
-                            StorageDeadOrDrop::BoxedStorageDead
-                        }
-                        StorageDeadOrDrop::Destructor(_) => base_access,
-                    },
-                    ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = Place::ty_from(
-                            &place.base,
-                            proj_base,
-                            *self.body,
-                            tcx
-                        ).ty;
-                        match base_ty.kind {
-                            ty::Adt(def, _) if def.has_dtor(tcx) => {
-                                // Report the outermost adt with a destructor
-                                match base_access {
-                                    StorageDeadOrDrop::Destructor(_) => base_access,
-                                    StorageDeadOrDrop::LocalStorageDead
-                                    | StorageDeadOrDrop::BoxedStorageDead => {
-                                        StorageDeadOrDrop::Destructor(base_ty)
-                                    }
-                                }
-                            }
-                            _ => base_access,
-                        }
-                    }
-
-                    ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. }
-                    | ProjectionElem::Index(_) => base_access,
-                }
-            }
-        }
-    }
-
-    /// Describe the reason for the fake borrow that was assigned to `place`.
-    fn classify_immutable_section(&self, place: &Place<'tcx>) -> Option<&'static str> {
-        use rustc::mir::visit::Visitor;
-        struct FakeReadCauseFinder<'a, 'tcx> {
-            place: &'a Place<'tcx>,
-            cause: Option<FakeReadCause>,
-        }
-        impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'_, 'tcx> {
-            fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
-                match statement {
-                    Statement {
-                        kind: StatementKind::FakeRead(cause, box ref place),
-                        ..
-                    } if *place == *self.place => {
-                        self.cause = Some(*cause);
-                    }
-                    _ => (),
-                }
-            }
-        }
-        let mut visitor = FakeReadCauseFinder { place, cause: None };
-        visitor.visit_body(self.body);
-        match visitor.cause {
-            Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
-            Some(FakeReadCause::ForIndex) => Some("indexing expression"),
-            _ => None,
-        }
-    }
-
-    /// Annotate argument and return type of function and closure with (synthesized) lifetime for
-    /// borrow of local value that does not live long enough.
-    fn annotate_argument_and_return_for_borrow(
-        &self,
-        borrow: &BorrowData<'tcx>,
-    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
-        // Define a fallback for when we can't match a closure.
-        let fallback = || {
-            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
-            if is_closure {
-                None
-            } else {
-                let ty = self.infcx.tcx.type_of(self.mir_def_id);
-                match ty.kind {
-                    ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
-                        self.mir_def_id,
-                        self.infcx.tcx.fn_sig(self.mir_def_id),
-                    ),
-                    _ => None,
-                }
-            }
-        };
-
-        // In order to determine whether we need to annotate, we need to check whether the reserve
-        // place was an assignment into a temporary.
-        //
-        // If it was, we check whether or not that temporary is eventually assigned into the return
-        // place. If it was, we can add annotations about the function's return type and arguments
-        // and it'll make sense.
-        let location = borrow.reserve_location;
-        debug!(
-            "annotate_argument_and_return_for_borrow: location={:?}",
-            location
-        );
-        if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
-             = &self.body[location.block].statements.get(location.statement_index)
-        {
-            debug!(
-                "annotate_argument_and_return_for_borrow: reservation={:?}",
-                reservation
-            );
-            // Check that the initial assignment of the reserve location is into a temporary.
-            let mut target = match reservation.as_local() {
-                Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
-                _ => return None,
-            };
-
-            // Next, look through the rest of the block, checking if we are assigning the
-            // `target` (that is, the place that contains our borrow) to anything.
-            let mut annotated_closure = None;
-            for stmt in &self.body[location.block].statements[location.statement_index + 1..]
-            {
-                debug!(
-                    "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
-                    target, stmt
-                );
-                if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
-                    if let Some(assigned_to) = place.as_local() {
-                        debug!(
-                            "annotate_argument_and_return_for_borrow: assigned_to={:?} \
-                             rvalue={:?}",
-                            assigned_to, rvalue
-                        );
-                        // Check if our `target` was captured by a closure.
-                        if let Rvalue::Aggregate(
-                            box AggregateKind::Closure(def_id, substs),
-                            operands,
-                        ) = rvalue
-                        {
-                            for operand in operands {
-                                let assigned_from = match operand {
-                                    Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                        assigned_from
-                                    }
-                                    _ => continue,
-                                };
-                                debug!(
-                                    "annotate_argument_and_return_for_borrow: assigned_from={:?}",
-                                    assigned_from
-                                );
-
-                                // Find the local from the operand.
-                                let assigned_from_local = match assigned_from.local_or_deref_local()
-                                {
-                                    Some(local) => local,
-                                    None => continue,
-                                };
-
-                                if assigned_from_local != target {
-                                    continue;
-                                }
-
-                                // If a closure captured our `target` and then assigned
-                                // into a place then we should annotate the closure in
-                                // case it ends up being assigned into the return place.
-                                annotated_closure = self.annotate_fn_sig(
-                                    *def_id,
-                                    self.infcx.closure_sig(*def_id, *substs),
-                                );
-                                debug!(
-                                    "annotate_argument_and_return_for_borrow: \
-                                     annotated_closure={:?} assigned_from_local={:?} \
-                                     assigned_to={:?}",
-                                    annotated_closure, assigned_from_local, assigned_to
-                                );
-
-                                if assigned_to == mir::RETURN_PLACE {
-                                    // If it was assigned directly into the return place, then
-                                    // return now.
-                                    return annotated_closure;
-                                } else {
-                                    // Otherwise, update the target.
-                                    target = assigned_to;
-                                }
-                            }
-
-                            // If none of our closure's operands matched, then skip to the next
-                            // statement.
-                            continue;
-                        }
-
-                        // Otherwise, look at other types of assignment.
-                        let assigned_from = match rvalue {
-                            Rvalue::Ref(_, _, assigned_from) => assigned_from,
-                            Rvalue::Use(operand) => match operand {
-                                Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                    assigned_from
-                                }
-                                _ => continue,
-                            },
-                            _ => continue,
-                        };
-                        debug!(
-                            "annotate_argument_and_return_for_borrow: \
-                             assigned_from={:?}",
-                            assigned_from,
-                        );
-
-                        // Find the local from the rvalue.
-                        let assigned_from_local = match assigned_from.local_or_deref_local() {
-                            Some(local) => local,
-                            None => continue,
-                        };
-                        debug!(
-                            "annotate_argument_and_return_for_borrow: \
-                             assigned_from_local={:?}",
-                            assigned_from_local,
-                        );
-
-                        // Check if our local matches the target - if so, we've assigned our
-                        // borrow to a new place.
-                        if assigned_from_local != target {
-                            continue;
-                        }
-
-                        // If we assigned our `target` into a new place, then we should
-                        // check if it was the return place.
-                        debug!(
-                            "annotate_argument_and_return_for_borrow: \
-                             assigned_from_local={:?} assigned_to={:?}",
-                            assigned_from_local, assigned_to
-                        );
-                        if assigned_to == mir::RETURN_PLACE {
-                            // If it was then return the annotated closure if there was one,
-                            // else, annotate this function.
-                            return annotated_closure.or_else(fallback);
-                        }
-
-                        // If we didn't assign into the return place, then we just update
-                        // the target.
-                        target = assigned_to;
-                    }
-                }
-            }
-
-            // Check the terminator if we didn't find anything in the statements.
-            let terminator = &self.body[location.block].terminator();
-            debug!(
-                "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
-                target, terminator
-            );
-            if let TerminatorKind::Call {
-                destination: Some((place, _)),
-                args,
-                ..
-            } = &terminator.kind
-            {
-                if let Some(assigned_to) = place.as_local() {
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
-                        assigned_to, args
-                    );
-                    for operand in args {
-                        let assigned_from = match operand {
-                            Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                assigned_from
-                            }
-                            _ => continue,
-                        };
-                        debug!(
-                            "annotate_argument_and_return_for_borrow: assigned_from={:?}",
-                            assigned_from,
-                        );
-
-                        if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
-                            debug!(
-                                "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
-                                assigned_from_local,
-                            );
-
-                            if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
-                                return annotated_closure.or_else(fallback);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        // If we haven't found an assignment into the return place, then we need not add
-        // any annotations.
-        debug!("annotate_argument_and_return_for_borrow: none found");
-        None
-    }
-
-    /// Annotate the first argument and return type of a function signature if they are
-    /// references.
-    fn annotate_fn_sig(
-        &self,
-        did: DefId,
-        sig: ty::PolyFnSig<'tcx>,
-    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
-        debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
-        let is_closure = self.infcx.tcx.is_closure(did);
-        let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(did)?;
-        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
-
-        // We need to work out which arguments to highlight. We do this by looking
-        // at the return type, where there are three cases:
-        //
-        // 1. If there are named arguments, then we should highlight the return type and
-        //    highlight any of the arguments that are also references with that lifetime.
-        //    If there are no arguments that have the same lifetime as the return type,
-        //    then don't highlight anything.
-        // 2. The return type is a reference with an anonymous lifetime. If this is
-        //    the case, then we can take advantage of (and teach) the lifetime elision
-        //    rules.
-        //
-        //    We know that an error is being reported. So the arguments and return type
-        //    must satisfy the elision rules. Therefore, if there is a single argument
-        //    then that means the return type and first (and only) argument have the same
-        //    lifetime and the borrow isn't meeting that, we can highlight the argument
-        //    and return type.
-        //
-        //    If there are multiple arguments then the first argument must be self (else
-        //    it would not satisfy the elision rules), so we can highlight self and the
-        //    return type.
-        // 3. The return type is not a reference. In this case, we don't highlight
-        //    anything.
-        let return_ty = sig.output();
-        match return_ty.skip_binder().kind {
-            ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
-                // This is case 1 from above, return type is a named reference so we need to
-                // search for relevant arguments.
-                let mut arguments = Vec::new();
-                for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
-                    if let ty::Ref(argument_region, _, _) = argument.kind {
-                        if argument_region == return_region {
-                            // Need to use the `rustc::ty` types to compare against the
-                            // `return_region`. Then use the `rustc::hir` type to get only
-                            // the lifetime span.
-                            if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
-                                // With access to the lifetime, we can get
-                                // the span of it.
-                                arguments.push((*argument, lifetime.span));
-                            } else {
-                                bug!("ty type is a ref but hir type is not");
-                            }
-                        }
-                    }
-                }
-
-                // We need to have arguments. This shouldn't happen, but it's worth checking.
-                if arguments.is_empty() {
-                    return None;
-                }
-
-                // We use a mix of the HIR and the Ty types to get information
-                // as the HIR doesn't have full types for closure arguments.
-                let return_ty = *sig.output().skip_binder();
-                let mut return_span = fn_decl.output.span();
-                if let hir::FunctionRetTy::Return(ty) = &fn_decl.output {
-                    if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
-                        return_span = lifetime.span;
-                    }
-                }
-
-                Some(AnnotatedBorrowFnSignature::NamedFunction {
-                    arguments,
-                    return_ty,
-                    return_span,
-                })
-            }
-            ty::Ref(_, _, _) if is_closure => {
-                // This is case 2 from above but only for closures, return type is anonymous
-                // reference so we select
-                // the first argument.
-                let argument_span = fn_decl.inputs.first()?.span;
-                let argument_ty = sig.inputs().skip_binder().first()?;
-
-                // Closure arguments are wrapped in a tuple, so we need to get the first
-                // from that.
-                if let ty::Tuple(elems) = argument_ty.kind {
-                    let argument_ty = elems.first()?.expect_ty();
-                    if let ty::Ref(_, _, _) = argument_ty.kind {
-                        return Some(AnnotatedBorrowFnSignature::Closure {
-                            argument_ty,
-                            argument_span,
-                        });
-                    }
-                }
-
-                None
-            }
-            ty::Ref(_, _, _) => {
-                // This is also case 2 from above but for functions, return type is still an
-                // anonymous reference so we select the first argument.
-                let argument_span = fn_decl.inputs.first()?.span;
-                let argument_ty = sig.inputs().skip_binder().first()?;
-
-                let return_span = fn_decl.output.span();
-                let return_ty = *sig.output().skip_binder();
-
-                // We expect the first argument to be a reference.
-                match argument_ty.kind {
-                    ty::Ref(_, _, _) => {}
-                    _ => return None,
-                }
-
-                Some(AnnotatedBorrowFnSignature::AnonymousFunction {
-                    argument_ty,
-                    argument_span,
-                    return_ty,
-                    return_span,
-                })
-            }
-            _ => {
-                // This is case 3 from above, return type is not a reference so don't highlight
-                // anything.
-                None
-            }
-        }
-    }
-}
-
-#[derive(Debug)]
-enum AnnotatedBorrowFnSignature<'tcx> {
-    NamedFunction {
-        arguments: Vec<(Ty<'tcx>, Span)>,
-        return_ty: Ty<'tcx>,
-        return_span: Span,
-    },
-    AnonymousFunction {
-        argument_ty: Ty<'tcx>,
-        argument_span: Span,
-        return_ty: Ty<'tcx>,
-        return_span: Span,
-    },
-    Closure {
-        argument_ty: Ty<'tcx>,
-        argument_span: Span,
-    },
-}
-
-impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
-    /// Annotate the provided diagnostic with information about borrow from the fn signature that
-    /// helps explain.
-    pub(super) fn emit(
-        &self,
-        cx: &mut MirBorrowckCtxt<'_, 'tcx>,
-        diag: &mut DiagnosticBuilder<'_>,
-    ) -> String {
-        match self {
-            AnnotatedBorrowFnSignature::Closure {
-                argument_ty,
-                argument_span,
-            } => {
-                diag.span_label(
-                    *argument_span,
-                    format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
-                );
-
-                cx.get_region_name_for_ty(argument_ty, 0)
-            }
-            AnnotatedBorrowFnSignature::AnonymousFunction {
-                argument_ty,
-                argument_span,
-                return_ty,
-                return_span,
-            } => {
-                let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
-                diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
-
-                let return_ty_name = cx.get_name_for_ty(return_ty, 0);
-                let types_equal = return_ty_name == argument_ty_name;
-                diag.span_label(
-                    *return_span,
-                    format!(
-                        "{}has type `{}`",
-                        if types_equal { "also " } else { "" },
-                        return_ty_name,
-                    ),
-                );
-
-                diag.note(
-                    "argument and return type have the same lifetime due to lifetime elision rules",
-                );
-                diag.note(
-                    "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
-                     lifetime-syntax.html#lifetime-elision>",
-                );
-
-                cx.get_region_name_for_ty(return_ty, 0)
-            }
-            AnnotatedBorrowFnSignature::NamedFunction {
-                arguments,
-                return_ty,
-                return_span,
-            } => {
-                // Region of return type and arguments checked to be the same earlier.
-                let region_name = cx.get_region_name_for_ty(return_ty, 0);
-                for (_, argument_span) in arguments {
-                    diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
-                }
-
-                diag.span_label(
-                    *return_span,
-                    format!("also has lifetime `{}`", region_name,),
-                );
-
-                diag.help(&format!(
-                    "use data from the highlighted arguments which match the `{}` lifetime of \
-                     the return type",
-                    region_name,
-                ));
-
-                region_name
-            }
-        }
-    }
-}
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
new file mode 100644 (file)
index 0000000..d14957b
--- /dev/null
@@ -0,0 +1,2160 @@
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::hir::{AsyncGeneratorKind, GeneratorKind};
+use rustc::mir::{
+    self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
+    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
+    PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+};
+use rustc::ty::{self, Ty};
+use rustc::traits::error_reporting::suggest_constraining_type_param;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_index::vec::Idx;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use syntax_pos::Span;
+use syntax::source_map::DesugaringKind;
+
+use crate::dataflow::drop_flag_effects;
+use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
+use crate::util::borrowck_errors;
+
+use crate::borrow_check::{
+    prefixes::IsPrefixOf,
+    WriteKind,
+    borrow_set::BorrowData,
+    MirBorrowckCtxt, InitializationRequiringAction, PrefixSet
+};
+
+use super::{
+    IncludingDowncast, UseSpans, RegionName, RegionNameSource,
+    explain_borrow::BorrowExplanation,
+};
+
+#[derive(Debug)]
+struct MoveSite {
+    /// Index of the "move out" that we found. The `MoveData` can
+    /// then tell us where the move occurred.
+    moi: MoveOutIndex,
+
+    /// `true` if we traversed a back edge while walking from the point
+    /// of error to the move site.
+    traversed_back_edge: bool
+}
+
+/// Which case a StorageDeadOrDrop is for.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum StorageDeadOrDrop<'tcx> {
+    LocalStorageDead,
+    BoxedStorageDead,
+    Destructor(Ty<'tcx>),
+}
+
+impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+    pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
+        &mut self,
+        location: Location,
+        desired_action: InitializationRequiringAction,
+        (moved_place, used_place, span): (PlaceRef<'cx, 'tcx>, PlaceRef<'cx, 'tcx>, Span),
+        mpi: MovePathIndex,
+    ) {
+        debug!(
+            "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
+             moved_place={:?} used_place={:?} span={:?} mpi={:?}",
+            location, desired_action, moved_place, used_place, span, mpi
+        );
+
+        let use_spans = self.move_spans(moved_place, location)
+            .or_else(|| self.borrow_spans(span, location));
+        let span = use_spans.args_or_use();
+
+        let move_site_vec = self.get_moved_indexes(location, mpi);
+        debug!(
+            "report_use_of_moved_or_uninitialized: move_site_vec={:?}",
+            move_site_vec
+        );
+        let move_out_indices: Vec<_> = move_site_vec
+            .iter()
+            .map(|move_site| move_site.moi)
+            .collect();
+
+        if move_out_indices.is_empty() {
+            let root_place = self
+                .prefixes(used_place, PrefixSet::All)
+                .last()
+                .unwrap();
+
+            if !self.uninitialized_error_reported.insert(root_place) {
+                debug!(
+                    "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
+                    root_place
+                );
+                return;
+            }
+
+            let item_msg = match self.describe_place_with_options(used_place,
+                                                                  IncludingDowncast(true)) {
+                Some(name) => format!("`{}`", name),
+                None => "value".to_owned(),
+            };
+            let mut err = self.cannot_act_on_uninitialized_variable(
+                span,
+                desired_action.as_noun(),
+                &self.describe_place_with_options(moved_place, IncludingDowncast(true))
+                    .unwrap_or_else(|| "_".to_owned()),
+            );
+            err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
+
+            use_spans.var_span_label(
+                &mut err,
+                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
+            );
+
+            err.buffer(&mut self.errors_buffer);
+        } else {
+            if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
+                if self.prefixes(*reported_place, PrefixSet::All)
+                    .any(|p| p == used_place)
+                {
+                    debug!(
+                        "report_use_of_moved_or_uninitialized place: error suppressed \
+                         mois={:?}",
+                        move_out_indices
+                    );
+                    return;
+                }
+            }
+
+            let msg = ""; //FIXME: add "partially " or "collaterally "
+
+            let mut err = self.cannot_act_on_moved_value(
+                span,
+                desired_action.as_noun(),
+                msg,
+                self.describe_place_with_options(moved_place, IncludingDowncast(true)),
+            );
+
+            self.add_moved_or_invoked_closure_note(
+                location,
+                used_place,
+                &mut err,
+            );
+
+            let mut is_loop_move = false;
+            let is_partial_move = move_site_vec.iter().any(|move_site| {
+                let move_out = self.move_data.moves[(*move_site).moi];
+                let moved_place = &self.move_data.move_paths[move_out.path].place;
+                used_place != moved_place.as_ref()
+                    && used_place.is_prefix_of(moved_place.as_ref())
+            });
+            for move_site in &move_site_vec {
+                let move_out = self.move_data.moves[(*move_site).moi];
+                let moved_place = &self.move_data.move_paths[move_out.path].place;
+
+                let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
+                let move_span = move_spans.args_or_use();
+
+                let move_msg = if move_spans.for_closure() {
+                    " into closure"
+                } else {
+                    ""
+                };
+
+                if span == move_span {
+                    err.span_label(
+                        span,
+                        format!("value moved{} here, in previous iteration of loop", move_msg),
+                    );
+                    is_loop_move = true;
+                } else if move_site.traversed_back_edge {
+                    err.span_label(
+                        move_span,
+                        format!(
+                            "value moved{} here, in previous iteration of loop",
+                            move_msg
+                        ),
+                    );
+                } else {
+                    err.span_label(move_span, format!("value moved{} here", move_msg));
+                    move_spans.var_span_label(
+                        &mut err,
+                        format!("variable moved due to use{}", move_spans.describe()),
+                    );
+                }
+                if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
+                    let sess = self.infcx.tcx.sess;
+                    if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
+                        err.span_suggestion(
+                            move_span,
+                            "consider borrowing to avoid moving into the for loop",
+                            format!("&{}", snippet),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+
+            use_spans.var_span_label(
+                &mut err,
+                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
+            );
+
+            if !is_loop_move {
+                err.span_label(
+                    span,
+                    format!(
+                        "value {} here {}",
+                        desired_action.as_verb_in_past_tense(),
+                        if is_partial_move { "after partial move" } else { "after move" },
+                    ),
+                );
+            }
+
+            let ty = Place::ty_from(
+                used_place.base,
+                used_place.projection,
+                *self.body,
+                self.infcx.tcx
+            ).ty;
+            let needs_note = match ty.kind {
+                ty::Closure(id, _) => {
+                    let tables = self.infcx.tcx.typeck_tables_of(id);
+                    let hir_id = self.infcx.tcx.hir().as_local_hir_id(id).unwrap();
+
+                    tables.closure_kind_origins().get(hir_id).is_none()
+                }
+                _ => true,
+            };
+
+            if needs_note {
+                let mpi = self.move_data.moves[move_out_indices[0]].path;
+                let place = &self.move_data.move_paths[mpi].place;
+
+                let ty = place.ty(*self.body, self.infcx.tcx).ty;
+                let opt_name =
+                    self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
+                let note_msg = match opt_name {
+                    Some(ref name) => format!("`{}`", name),
+                    None => "value".to_owned(),
+                };
+                if let ty::Param(param_ty) = ty.kind {
+                    let tcx = self.infcx.tcx;
+                    let generics = tcx.generics_of(self.mir_def_id);
+                    let param = generics.type_param(&param_ty, tcx);
+                    let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
+                    suggest_constraining_type_param(
+                        generics,
+                        &mut err,
+                        &param.name.as_str(),
+                        "Copy",
+                        tcx.sess.source_map(),
+                        span,
+                    );
+                }
+                let span = if let Some(local) = place.as_local() {
+                    let decl = &self.body.local_decls[local];
+                    Some(decl.source_info.span)
+                } else {
+                    None
+                };
+                self.note_type_does_not_implement_copy(
+                    &mut err,
+                    &note_msg,
+                    ty,
+                    span,
+                );
+            }
+
+            if let Some((_, mut old_err)) = self.move_error_reported
+                .insert(move_out_indices, (used_place, err))
+            {
+                // Cancel the old error so it doesn't ICE.
+                old_err.cancel();
+            }
+        }
+    }
+
+    pub(in crate::borrow_check) fn report_move_out_while_borrowed(
+        &mut self,
+        location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        borrow: &BorrowData<'tcx>,
+    ) {
+        debug!(
+            "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
+            location, place, span, borrow
+        );
+        let value_msg = match self.describe_place(place.as_ref()) {
+            Some(name) => format!("`{}`", name),
+            None => "value".to_owned(),
+        };
+        let borrow_msg = match self.describe_place(borrow.borrowed_place.as_ref()) {
+            Some(name) => format!("`{}`", name),
+            None => "value".to_owned(),
+        };
+
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.args_or_use();
+
+        let move_spans = self.move_spans(place.as_ref(), location);
+        let span = move_spans.args_or_use();
+
+        let mut err = self.cannot_move_when_borrowed(
+            span,
+            &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
+        );
+        err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
+        err.span_label(span, format!("move out of {} occurs here", value_msg));
+
+        borrow_spans.var_span_label(
+            &mut err,
+            format!("borrow occurs due to use{}", borrow_spans.describe())
+        );
+
+        move_spans.var_span_label(
+            &mut err,
+            format!("move occurs due to use{}", move_spans.describe())
+        );
+
+        self.explain_why_borrow_contains_point(
+            location,
+            borrow,
+            None,
+        ).add_explanation_to_diagnostic(
+            self.infcx.tcx,
+            &self.body,
+            &self.local_names,
+            &mut err,
+            "",
+            Some(borrow_span),
+        );
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
+        &mut self,
+        location: Location,
+        (place, _span): (&Place<'tcx>, Span),
+        borrow: &BorrowData<'tcx>,
+    ) -> DiagnosticBuilder<'cx> {
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.args_or_use();
+
+        // Conflicting borrows are reported separately, so only check for move
+        // captures.
+        let use_spans = self.move_spans(place.as_ref(), location);
+        let span = use_spans.var_or_use();
+
+        let mut err = self.cannot_use_when_mutably_borrowed(
+            span,
+            &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
+            borrow_span,
+            &self.describe_place(borrow.borrowed_place.as_ref())
+                .unwrap_or_else(|| "_".to_owned()),
+        );
+
+        borrow_spans.var_span_label(&mut err, {
+            let place = &borrow.borrowed_place;
+            let desc_place =
+                self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned());
+
+            format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
+        });
+
+        self.explain_why_borrow_contains_point(location, borrow, None)
+            .add_explanation_to_diagnostic(
+                self.infcx.tcx,
+                &self.body,
+                &self.local_names,
+                &mut err,
+                "",
+                None,
+            );
+        err
+    }
+
+    pub(in crate::borrow_check) fn report_conflicting_borrow(
+        &mut self,
+        location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        gen_borrow_kind: BorrowKind,
+        issued_borrow: &BorrowData<'tcx>,
+    ) -> DiagnosticBuilder<'cx> {
+        let issued_spans = self.retrieve_borrow_spans(issued_borrow);
+        let issued_span = issued_spans.args_or_use();
+
+        let borrow_spans = self.borrow_spans(span, location);
+        let span = borrow_spans.args_or_use();
+
+        let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
+            "generator"
+        } else {
+            "closure"
+        };
+
+        let (desc_place, msg_place, msg_borrow, union_type_name) =
+            self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
+
+        let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
+        let second_borrow_desc = if explanation.is_explained() {
+            "second "
+        } else {
+            ""
+        };
+
+        // FIXME: supply non-"" `opt_via` when appropriate
+        let first_borrow_desc;
+        let mut err = match (
+            gen_borrow_kind,
+            issued_borrow.kind,
+        ) {
+            (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
+                first_borrow_desc = "mutable ";
+                self.cannot_reborrow_already_borrowed(
+                    span,
+                    &desc_place,
+                    &msg_place,
+                    "immutable",
+                    issued_span,
+                    "it",
+                    "mutable",
+                    &msg_borrow,
+                    None,
+                )
+            }
+            (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
+                first_borrow_desc = "immutable ";
+                self.cannot_reborrow_already_borrowed(
+                    span,
+                    &desc_place,
+                    &msg_place,
+                    "mutable",
+                    issued_span,
+                    "it",
+                    "immutable",
+                    &msg_borrow,
+                    None,
+                )
+            }
+
+            (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
+                first_borrow_desc = "first ";
+                self.cannot_mutably_borrow_multiply(
+                    span,
+                    &desc_place,
+                    &msg_place,
+                    issued_span,
+                    &msg_borrow,
+                    None,
+                )
+            }
+
+            (BorrowKind::Unique, BorrowKind::Unique) => {
+                first_borrow_desc = "first ";
+                self.cannot_uniquely_borrow_by_two_closures(
+                    span,
+                    &desc_place,
+                    issued_span,
+                    None,
+                )
+            }
+
+            (BorrowKind::Mut { .. }, BorrowKind::Shallow)
+            | (BorrowKind::Unique, BorrowKind::Shallow) => {
+                if let Some(immutable_section_description) = self.classify_immutable_section(
+                    &issued_borrow.assigned_place,
+                ) {
+                    let mut err = self.cannot_mutate_in_immutable_section(
+                        span,
+                        issued_span,
+                        &desc_place,
+                        immutable_section_description,
+                        "mutably borrow",
+                    );
+                    borrow_spans.var_span_label(
+                        &mut err,
+                        format!(
+                            "borrow occurs due to use of `{}`{}",
+                            desc_place,
+                            borrow_spans.describe(),
+                        ),
+                    );
+
+                    return err;
+                } else {
+                    first_borrow_desc = "immutable ";
+                    self.cannot_reborrow_already_borrowed(
+                        span,
+                        &desc_place,
+                        &msg_place,
+                        "mutable",
+                        issued_span,
+                        "it",
+                        "immutable",
+                        &msg_borrow,
+                        None,
+                    )
+                }
+            }
+
+            (BorrowKind::Unique, _) => {
+                first_borrow_desc = "first ";
+                self.cannot_uniquely_borrow_by_one_closure(
+                    span,
+                    container_name,
+                    &desc_place,
+                    "",
+                    issued_span,
+                    "it",
+                    "",
+                    None,
+                )
+            },
+
+            (BorrowKind::Shared, BorrowKind::Unique) => {
+                first_borrow_desc = "first ";
+                self.cannot_reborrow_already_uniquely_borrowed(
+                    span,
+                    container_name,
+                    &desc_place,
+                    "",
+                    "immutable",
+                    issued_span,
+                    "",
+                    None,
+                    second_borrow_desc,
+                )
+            }
+
+            (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
+                first_borrow_desc = "first ";
+                self.cannot_reborrow_already_uniquely_borrowed(
+                    span,
+                    container_name,
+                    &desc_place,
+                    "",
+                    "mutable",
+                    issued_span,
+                    "",
+                    None,
+                    second_borrow_desc,
+                )
+            }
+
+            (BorrowKind::Shared, BorrowKind::Shared)
+            | (BorrowKind::Shared, BorrowKind::Shallow)
+            | (BorrowKind::Shallow, BorrowKind::Mut { .. })
+            | (BorrowKind::Shallow, BorrowKind::Unique)
+            | (BorrowKind::Shallow, BorrowKind::Shared)
+            | (BorrowKind::Shallow, BorrowKind::Shallow) => unreachable!(),
+        };
+
+        if issued_spans == borrow_spans {
+            borrow_spans.var_span_label(
+                &mut err,
+                format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()),
+            );
+        } else {
+            let borrow_place = &issued_borrow.borrowed_place;
+            let borrow_place_desc = self.describe_place(borrow_place.as_ref())
+                                        .unwrap_or_else(|| "_".to_owned());
+            issued_spans.var_span_label(
+                &mut err,
+                format!(
+                    "first borrow occurs due to use of `{}`{}",
+                    borrow_place_desc,
+                    issued_spans.describe(),
+                ),
+            );
+
+            borrow_spans.var_span_label(
+                &mut err,
+                format!(
+                    "second borrow occurs due to use of `{}`{}",
+                    desc_place,
+                    borrow_spans.describe(),
+                ),
+            );
+        }
+
+        if union_type_name != "" {
+            err.note(&format!(
+                "`{}` is a field of the union `{}`, so it overlaps the field `{}`",
+                msg_place, union_type_name, msg_borrow,
+            ));
+        }
+
+        explanation.add_explanation_to_diagnostic(
+            self.infcx.tcx,
+            &self.body,
+            &self.local_names,
+            &mut err,
+            first_borrow_desc,
+            None,
+        );
+
+        err
+    }
+
+    /// Returns the description of the root place for a conflicting borrow and the full
+    /// descriptions of the places that caused the conflict.
+    ///
+    /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
+    /// attempted while a shared borrow is live, then this function will return:
+    ///
+    ///     ("x", "", "")
+    ///
+    /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
+    /// a shared borrow of another field `x.y`, then this function will return:
+    ///
+    ///     ("x", "x.z", "x.y")
+    ///
+    /// In the more complex union case, where the union is a field of a struct, then if a mutable
+    /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
+    /// another field `x.u.y`, then this function will return:
+    ///
+    ///     ("x.u", "x.u.z", "x.u.y")
+    ///
+    /// This is used when creating error messages like below:
+    ///
+    /// >  cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
+    /// >  mutable (via `a.u.s.b`) [E0502]
+    pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
+        &self,
+        first_borrowed_place: &Place<'tcx>,
+        second_borrowed_place: &Place<'tcx>,
+    ) -> (String, String, String, String) {
+        // Define a small closure that we can use to check if the type of a place
+        // is a union.
+        let union_ty = |place_base, place_projection| {
+            let ty = Place::ty_from(
+                place_base,
+                place_projection,
+                *self.body,
+                self.infcx.tcx
+            ).ty;
+            ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
+        };
+        let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned());
+
+        // Start with an empty tuple, so we can use the functions on `Option` to reduce some
+        // code duplication (particularly around returning an empty description in the failure
+        // case).
+        Some(())
+            .filter(|_| {
+                // If we have a conflicting borrow of the same place, then we don't want to add
+                // an extraneous "via x.y" to our diagnostics, so filter out this case.
+                first_borrowed_place != second_borrowed_place
+            })
+            .and_then(|_| {
+                // We're going to want to traverse the first borrowed place to see if we can find
+                // field access to a union. If we find that, then we will keep the place of the
+                // union being accessed and the field that was being accessed so we can check the
+                // second borrowed place for the same union and a access to a different field.
+                let Place {
+                    base,
+                    projection,
+                } = first_borrowed_place;
+
+                let mut cursor = projection.as_ref();
+                while let [proj_base @ .., elem] = cursor {
+                    cursor = proj_base;
+
+                    match elem {
+                        ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
+                            return Some((PlaceRef {
+                                base: base,
+                                projection: proj_base,
+                            }, field));
+                        },
+                        _ => {},
+                    }
+                }
+                None
+            })
+            .and_then(|(target_base, target_field)| {
+                // With the place of a union and a field access into it, we traverse the second
+                // borrowed place and look for a access to a different field of the same union.
+                let Place {
+                    base,
+                    projection,
+                } = second_borrowed_place;
+
+                let mut cursor = projection.as_ref();
+                while let [proj_base @ .., elem] = cursor {
+                    cursor = proj_base;
+
+                    if let ProjectionElem::Field(field, _) = elem {
+                        if let Some(union_ty) = union_ty(base, proj_base) {
+                            if field != target_field
+                                && base == target_base.base
+                                && proj_base == target_base.projection {
+                                // FIXME when we avoid clone reuse describe_place closure
+                                let describe_base_place =  self.describe_place(PlaceRef {
+                                    base: base,
+                                    projection: proj_base,
+                                }).unwrap_or_else(|| "_".to_owned());
+
+                                return Some((
+                                    describe_base_place,
+                                    describe_place(first_borrowed_place.as_ref()),
+                                    describe_place(second_borrowed_place.as_ref()),
+                                    union_ty.to_string(),
+                                ));
+                            }
+                        }
+                    }
+                }
+                None
+            })
+            .unwrap_or_else(|| {
+                // If we didn't find a field access into a union, or both places match, then
+                // only return the description of the first place.
+                (
+                    describe_place(first_borrowed_place.as_ref()),
+                    "".to_string(),
+                    "".to_string(),
+                    "".to_string(),
+                )
+            })
+    }
+
+    /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
+    ///
+    /// This means that some data referenced by `borrow` needs to live
+    /// past the point where the StorageDeadOrDrop of `place` occurs.
+    /// This is usually interpreted as meaning that `place` has too
+    /// short a lifetime. (But sometimes it is more useful to report
+    /// it as a more direct conflict between the execution of a
+    /// `Drop::drop` with an aliasing borrow.)
+    pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
+        &mut self,
+        location: Location,
+        borrow: &BorrowData<'tcx>,
+        place_span: (&Place<'tcx>, Span),
+        kind: Option<WriteKind>,
+    ) {
+        debug!(
+            "report_borrowed_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}\
+             )",
+            location, borrow, place_span, kind
+        );
+
+        let drop_span = place_span.1;
+        let root_place = self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All)
+            .last()
+            .unwrap();
+
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.var_or_use();
+
+        assert!(root_place.projection.is_empty());
+        let proper_span = match root_place.base {
+            PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
+            _ => drop_span,
+        };
+
+        let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
+
+        if self.access_place_error_reported
+            .contains(&(Place {
+                base: root_place.base.clone(),
+                projection: root_place_projection,
+            }, borrow_span))
+        {
+            debug!(
+                "suppressing access_place error when borrow doesn't live long enough for {:?}",
+                borrow_span
+            );
+            return;
+        }
+
+        self.access_place_error_reported
+            .insert((Place {
+                base: root_place.base.clone(),
+                projection: root_place_projection,
+            }, borrow_span));
+
+        if let PlaceBase::Local(local) = borrow.borrowed_place.base {
+            if self.body.local_decls[local].is_ref_to_thread_local() {
+                let err = self.report_thread_local_value_does_not_live_long_enough(
+                    drop_span,
+                    borrow_span,
+                );
+                err.buffer(&mut self.errors_buffer);
+                return;
+            }
+        };
+
+        if let StorageDeadOrDrop::Destructor(dropped_ty) =
+            self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
+        {
+            // If a borrow of path `B` conflicts with drop of `D` (and
+            // we're not in the uninteresting case where `B` is a
+            // prefix of `D`), then report this as a more interesting
+            // destructor conflict.
+            if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
+                self.report_borrow_conflicts_with_destructor(
+                    location, borrow, place_span, kind, dropped_ty,
+                );
+                return;
+            }
+        }
+
+        let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
+
+        let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
+        let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
+
+        debug!(
+            "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
+            place_desc,
+            explanation
+        );
+        let err = match (place_desc, explanation) {
+            // If the outlives constraint comes from inside the closure,
+            // for example:
+            //
+            // let x = 0;
+            // let y = &x;
+            // Box::new(|| y) as Box<Fn() -> &'static i32>
+            //
+            // then just use the normal error. The closure isn't escaping
+            // and `move` will not help here.
+            (
+                Some(ref name),
+                BorrowExplanation::MustBeValidFor {
+                    category: category @ ConstraintCategory::Return,
+                    from_closure: false,
+                    ref region_name,
+                    span,
+                    ..
+                },
+            )
+            | (
+                Some(ref name),
+                BorrowExplanation::MustBeValidFor {
+                    category: category @ ConstraintCategory::CallArgument,
+                    from_closure: false,
+                    ref region_name,
+                    span,
+                    ..
+                },
+            ) if borrow_spans.for_closure() => self.report_escaping_closure_capture(
+                borrow_spans,
+                borrow_span,
+                region_name,
+                category,
+                span,
+                &format!("`{}`", name),
+            ),
+            (
+                Some(ref name),
+                BorrowExplanation::MustBeValidFor {
+                    category: category @ ConstraintCategory::OpaqueType,
+                    from_closure: false,
+                    ref region_name,
+                    span,
+                    ..
+                },
+
+            ) if borrow_spans.for_generator() => self.report_escaping_closure_capture(
+                borrow_spans,
+                borrow_span,
+                region_name,
+                category,
+                span,
+                &format!("`{}`", name),
+            ),
+            (
+                ref name,
+                BorrowExplanation::MustBeValidFor {
+                    category: ConstraintCategory::Assignment,
+                    from_closure: false,
+                    region_name: RegionName {
+                        source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
+                        ..
+                    },
+                    span,
+                    ..
+                },
+            ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
+            (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
+                location,
+                &name,
+                &borrow,
+                drop_span,
+                borrow_spans,
+                explanation,
+            ),
+            (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
+                location,
+                &borrow,
+                drop_span,
+                borrow_spans,
+                proper_span,
+                explanation,
+            ),
+        };
+
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    fn report_local_value_does_not_live_long_enough(
+        &mut self,
+        location: Location,
+        name: &str,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        borrow_spans: UseSpans,
+        explanation: BorrowExplanation,
+    ) -> DiagnosticBuilder<'cx> {
+        debug!(
+            "report_local_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}, {:?}\
+             )",
+            location, name, borrow, drop_span, borrow_spans
+        );
+
+        let borrow_span = borrow_spans.var_or_use();
+        if let BorrowExplanation::MustBeValidFor {
+            category,
+            span,
+            ref opt_place_desc,
+            from_closure: false,
+            ..
+        } = explanation {
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
+                borrow,
+                borrow_span,
+                span,
+                category,
+                opt_place_desc.as_ref(),
+            ) {
+                return diag;
+            }
+        }
+
+        let mut err = self.path_does_not_live_long_enough(
+            borrow_span,
+            &format!("`{}`", name),
+        );
+
+        if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
+            let region_name = annotation.emit(self, &mut err);
+
+            err.span_label(
+                borrow_span,
+                format!("`{}` would have to be valid for `{}`...", name, region_name),
+            );
+
+            if let Some(fn_hir_id) = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id) {
+                err.span_label(
+                    drop_span,
+                    format!(
+                        "...but `{}` will be dropped here, when the function `{}` returns",
+                        name,
+                        self.infcx.tcx.hir().name(fn_hir_id),
+                    ),
+                );
+
+                err.note(
+                    "functions cannot return a borrow to data owned within the function's scope, \
+                     functions can only return borrows to data passed as arguments",
+                );
+                err.note(
+                    "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
+                     references-and-borrowing.html#dangling-references>",
+                );
+            } else {
+                err.span_label(
+                    drop_span,
+                    format!("...but `{}` dropped here while still borrowed", name),
+                );
+            }
+
+            if let BorrowExplanation::MustBeValidFor { .. } = explanation {
+            } else {
+                explanation.add_explanation_to_diagnostic(
+                    self.infcx.tcx,
+                    &self.body,
+                    &self.local_names,
+                    &mut err,
+                    "",
+                    None,
+                );
+            }
+        } else {
+            err.span_label(borrow_span, "borrowed value does not live long enough");
+            err.span_label(
+                drop_span,
+                format!("`{}` dropped here while still borrowed", name),
+            );
+
+            let within = if borrow_spans.for_generator() {
+                " by generator"
+            } else {
+                ""
+            };
+
+            borrow_spans.args_span_label(
+                &mut err,
+                format!("value captured here{}", within),
+            );
+
+            explanation.add_explanation_to_diagnostic(
+                self.infcx.tcx, &self.body, &self.local_names, &mut err, "", None);
+        }
+
+        err
+    }
+
+    fn report_borrow_conflicts_with_destructor(
+        &mut self,
+        location: Location,
+        borrow: &BorrowData<'tcx>,
+        (place, drop_span): (&Place<'tcx>, Span),
+        kind: Option<WriteKind>,
+        dropped_ty: Ty<'tcx>,
+    ) {
+        debug!(
+            "report_borrow_conflicts_with_destructor(\
+             {:?}, {:?}, ({:?}, {:?}), {:?}\
+             )",
+            location, borrow, place, drop_span, kind,
+        );
+
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.var_or_use();
+
+        let mut err = self.cannot_borrow_across_destructor(borrow_span);
+
+        let what_was_dropped = match self.describe_place(place.as_ref()) {
+            Some(name) => format!("`{}`", name),
+            None => String::from("temporary value"),
+        };
+
+        let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
+            Some(borrowed) => format!(
+                "here, drop of {D} needs exclusive access to `{B}`, \
+                 because the type `{T}` implements the `Drop` trait",
+                D = what_was_dropped,
+                T = dropped_ty,
+                B = borrowed
+            ),
+            None => format!(
+                "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
+                D = what_was_dropped,
+                T = dropped_ty
+            ),
+        };
+        err.span_label(drop_span, label);
+
+        // Only give this note and suggestion if they could be relevant.
+        let explanation =
+            self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
+        match explanation {
+            BorrowExplanation::UsedLater { .. }
+            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
+                err.note("consider using a `let` binding to create a longer lived value");
+            }
+            _ => {}
+        }
+
+        explanation.add_explanation_to_diagnostic(
+            self.infcx.tcx,
+            &self.body,
+            &self.local_names,
+            &mut err,
+            "",
+            None,
+        );
+
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    fn report_thread_local_value_does_not_live_long_enough(
+        &mut self,
+        drop_span: Span,
+        borrow_span: Span,
+    ) -> DiagnosticBuilder<'cx> {
+        debug!(
+            "report_thread_local_value_does_not_live_long_enough(\
+             {:?}, {:?}\
+             )",
+            drop_span, borrow_span
+        );
+
+        let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
+
+        err.span_label(
+            borrow_span,
+            "thread-local variables cannot be borrowed beyond the end of the function",
+        );
+        err.span_label(drop_span, "end of enclosing function is here");
+
+        err
+    }
+
+    fn report_temporary_value_does_not_live_long_enough(
+        &mut self,
+        location: Location,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        borrow_spans: UseSpans,
+        proper_span: Span,
+        explanation: BorrowExplanation,
+    ) -> DiagnosticBuilder<'cx> {
+        debug!(
+            "report_temporary_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}\
+             )",
+            location, borrow, drop_span, proper_span
+        );
+
+        if let BorrowExplanation::MustBeValidFor {
+            category,
+            span,
+            from_closure: false,
+            ..
+        } = explanation {
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
+                borrow,
+                proper_span,
+                span,
+                category,
+                None,
+            ) {
+                return diag;
+            }
+        }
+
+        let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
+        err.span_label(
+            proper_span,
+            "creates a temporary which is freed while still in use",
+        );
+        err.span_label(
+            drop_span,
+            "temporary value is freed at the end of this statement",
+        );
+
+        match explanation {
+            BorrowExplanation::UsedLater(..)
+            | BorrowExplanation::UsedLaterInLoop(..)
+            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
+                // Only give this note and suggestion if it could be relevant.
+                err.note("consider using a `let` binding to create a longer lived value");
+            }
+            _ => {}
+        }
+        explanation.add_explanation_to_diagnostic(
+            self.infcx.tcx,
+            &self.body,
+            &self.local_names,
+            &mut err,
+            "",
+            None,
+        );
+
+        let within = if borrow_spans.for_generator() {
+            " by generator"
+        } else {
+            ""
+        };
+
+        borrow_spans.args_span_label(
+            &mut err,
+            format!("value captured here{}", within),
+        );
+
+        err
+    }
+
+    fn try_report_cannot_return_reference_to_local(
+        &self,
+        borrow: &BorrowData<'tcx>,
+        borrow_span: Span,
+        return_span: Span,
+        category: ConstraintCategory,
+        opt_place_desc: Option<&String>,
+    ) -> Option<DiagnosticBuilder<'cx>> {
+        let return_kind = match category {
+            ConstraintCategory::Return => "return",
+            ConstraintCategory::Yield => "yield",
+            _ => return None,
+        };
+
+        // FIXME use a better heuristic than Spans
+        let reference_desc
+            = if return_span == self.body.source_info(borrow.reserve_location).span {
+                "reference to"
+            } else {
+                "value referencing"
+            };
+
+        let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
+            let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
+                match self.body.local_kind(local) {
+                    LocalKind::ReturnPointer
+                    | LocalKind::Temp => bug!("temporary or return pointer with a name"),
+                    LocalKind::Var => "local variable ",
+                    LocalKind::Arg
+                    if !self.upvars.is_empty()
+                        && local == Local::new(1) => {
+                        "variable captured by `move` "
+                    }
+                    LocalKind::Arg => {
+                        "function parameter "
+                    }
+                }
+            } else {
+                "local data "
+            };
+            (
+                format!("{}`{}`", local_kind, place_desc),
+                format!("`{}` is borrowed here", place_desc),
+            )
+        } else {
+            let root_place = self.prefixes(borrow.borrowed_place.as_ref(),
+                                           PrefixSet::All)
+                .last()
+                .unwrap();
+            let local = if let PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [],
+            } = root_place {
+                local
+            } else {
+                bug!("try_report_cannot_return_reference_to_local: not a local")
+            };
+            match self.body.local_kind(*local) {
+                LocalKind::ReturnPointer | LocalKind::Temp => (
+                    "temporary value".to_string(),
+                    "temporary value created here".to_string(),
+                ),
+                LocalKind::Arg => (
+                    "function parameter".to_string(),
+                    "function parameter borrowed here".to_string(),
+                ),
+                LocalKind::Var => (
+                    "local binding".to_string(),
+                    "local binding introduced here".to_string(),
+                ),
+            }
+        };
+
+        let mut err = self.cannot_return_reference_to_local(
+            return_span,
+            return_kind,
+            reference_desc,
+            &place_desc,
+        );
+
+        if return_span != borrow_span {
+            err.span_label(borrow_span, note);
+        }
+
+        Some(err)
+    }
+
+    fn report_escaping_closure_capture(
+        &mut self,
+        use_span: UseSpans,
+        var_span: Span,
+        fr_name: &RegionName,
+        category: ConstraintCategory,
+        constraint_span: Span,
+        captured_var: &str,
+    ) -> DiagnosticBuilder<'cx> {
+        let tcx = self.infcx.tcx;
+        let args_span = use_span.args_or_use();
+        let mut err = self.cannot_capture_in_long_lived_closure(
+            args_span,
+            captured_var,
+            var_span,
+        );
+
+        let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
+            Ok(mut string) => {
+                if string.starts_with("async ") {
+                    string.insert_str(6, "move ");
+                } else if string.starts_with("async|") {
+                    string.insert_str(5, " move");
+                } else {
+                    string.insert_str(0, "move ");
+                };
+                string
+            },
+            Err(_) => "move |<args>| <body>".to_string()
+        };
+        let kind = match use_span.generator_kind() {
+            Some(generator_kind) => match generator_kind {
+                GeneratorKind::Async(async_kind) => match async_kind {
+                    AsyncGeneratorKind::Block => "async block",
+                    AsyncGeneratorKind::Closure => "async closure",
+                    _ => bug!("async block/closure expected, but async funtion found."),
+                },
+                GeneratorKind::Gen => "generator",
+            }
+            None => "closure",
+        };
+        err.span_suggestion(
+            args_span,
+            &format!(
+                "to force the {} to take ownership of {} (and any \
+                 other referenced variables), use the `move` keyword",
+                 kind,
+                 captured_var
+            ),
+            suggestion,
+            Applicability::MachineApplicable,
+        );
+
+        let msg = match category {
+            ConstraintCategory::Return => "closure is returned here".to_string(),
+            ConstraintCategory::OpaqueType => "generator is returned here".to_string(),
+            ConstraintCategory::CallArgument => {
+                fr_name.highlight_region_name(&mut err);
+                format!("function requires argument type to outlive `{}`", fr_name)
+            }
+            _ => bug!("report_escaping_closure_capture called with unexpected constraint \
+                       category: `{:?}`", category),
+        };
+        err.span_note(constraint_span, &msg);
+        err
+    }
+
+    fn report_escaping_data(
+        &mut self,
+        borrow_span: Span,
+        name: &Option<String>,
+        upvar_span: Span,
+        upvar_name: &str,
+        escape_span: Span,
+    ) -> DiagnosticBuilder<'cx> {
+        let tcx = self.infcx.tcx;
+
+        let escapes_from = if tcx.is_closure(self.mir_def_id) {
+            let tables = tcx.typeck_tables_of(self.mir_def_id);
+            let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index);
+            match tables.node_type(mir_hir_id).kind {
+                ty::Closure(..) => "closure",
+                ty::Generator(..) => "generator",
+                _ => bug!("Closure body doesn't have a closure or generator type"),
+            }
+        } else {
+            "function"
+        };
+
+        let mut err = borrowck_errors::borrowed_data_escapes_closure(
+            tcx,
+            escape_span,
+            escapes_from,
+        );
+
+        err.span_label(
+            upvar_span,
+            format!(
+                "`{}` is declared here, outside of the {} body",
+                upvar_name, escapes_from
+            ),
+        );
+
+        err.span_label(
+            borrow_span,
+            format!(
+                "borrow is only valid in the {} body",
+                escapes_from
+            ),
+        );
+
+        if let Some(name) = name {
+            err.span_label(
+                escape_span,
+                format!("reference to `{}` escapes the {} body here", name, escapes_from),
+            );
+        } else {
+            err.span_label(
+                escape_span,
+                format!("reference escapes the {} body here", escapes_from),
+            );
+        }
+
+        err
+    }
+
+    fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
+        let mut stack = Vec::new();
+        stack.extend(self.body.predecessor_locations(location).map(|predecessor| {
+            let is_back_edge = location.dominates(predecessor, &self.dominators);
+            (predecessor, is_back_edge)
+        }));
+
+        let mut visited = FxHashSet::default();
+        let mut result = vec![];
+
+        'dfs: while let Some((location, is_back_edge)) = stack.pop() {
+            debug!(
+                "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
+                location, is_back_edge
+            );
+
+            if !visited.insert(location) {
+                continue;
+            }
+
+            // check for moves
+            let stmt_kind = self.body[location.block]
+                .statements
+                .get(location.statement_index)
+                .map(|s| &s.kind);
+            if let Some(StatementKind::StorageDead(..)) = stmt_kind {
+                // this analysis only tries to find moves explicitly
+                // written by the user, so we ignore the move-outs
+                // created by `StorageDead` and at the beginning
+                // of a function.
+            } else {
+                // If we are found a use of a.b.c which was in error, then we want to look for
+                // moves not only of a.b.c but also a.b and a.
+                //
+                // Note that the moves data already includes "parent" paths, so we don't have to
+                // worry about the other case: that is, if there is a move of a.b.c, it is already
+                // marked as a move of a.b and a as well, so we will generate the correct errors
+                // there.
+                let mut mpis = vec![mpi];
+                let move_paths = &self.move_data.move_paths;
+                mpis.extend(move_paths[mpi].parents(move_paths));
+
+                for moi in &self.move_data.loc_map[location] {
+                    debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
+                    if mpis.contains(&self.move_data.moves[*moi].path) {
+                        debug!("report_use_of_moved_or_uninitialized: found");
+                        result.push(MoveSite {
+                            moi: *moi,
+                            traversed_back_edge: is_back_edge,
+                        });
+
+                        // Strictly speaking, we could continue our DFS here. There may be
+                        // other moves that can reach the point of error. But it is kind of
+                        // confusing to highlight them.
+                        //
+                        // Example:
+                        //
+                        // ```
+                        // let a = vec![];
+                        // let b = a;
+                        // let c = a;
+                        // drop(a); // <-- current point of error
+                        // ```
+                        //
+                        // Because we stop the DFS here, we only highlight `let c = a`,
+                        // and not `let b = a`. We will of course also report an error at
+                        // `let c = a` which highlights `let b = a` as the move.
+                        continue 'dfs;
+                    }
+                }
+            }
+
+            // check for inits
+            let mut any_match = false;
+            drop_flag_effects::for_location_inits(
+                self.infcx.tcx,
+                &self.body,
+                self.move_data,
+                location,
+                |m| {
+                    if m == mpi {
+                        any_match = true;
+                    }
+                },
+            );
+            if any_match {
+                continue 'dfs;
+            }
+
+            stack.extend(self.body.predecessor_locations(location).map(|predecessor| {
+                let back_edge = location.dominates(predecessor, &self.dominators);
+                (predecessor, is_back_edge || back_edge)
+            }));
+        }
+
+        result
+    }
+
+    pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
+        &mut self,
+        location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        loan: &BorrowData<'tcx>,
+    ) {
+        let loan_spans = self.retrieve_borrow_spans(loan);
+        let loan_span = loan_spans.args_or_use();
+
+        if loan.kind == BorrowKind::Shallow {
+            if let Some(section) = self.classify_immutable_section(&loan.assigned_place) {
+                let mut err = self.cannot_mutate_in_immutable_section(
+                    span,
+                    loan_span,
+                    &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
+                    section,
+                    "assign",
+                );
+                loan_spans.var_span_label(
+                    &mut err,
+                    format!("borrow occurs due to use{}", loan_spans.describe()),
+                );
+
+                err.buffer(&mut self.errors_buffer);
+
+                return;
+            }
+        }
+
+        let mut err = self.cannot_assign_to_borrowed(
+            span,
+            loan_span,
+            &self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
+        );
+
+        loan_spans.var_span_label(
+            &mut err,
+            format!("borrow occurs due to use{}", loan_spans.describe()),
+        );
+
+        self.explain_why_borrow_contains_point(location, loan, None)
+            .add_explanation_to_diagnostic(
+                self.infcx.tcx,
+                &self.body,
+                &self.local_names,
+                &mut err,
+                "",
+                None,
+            );
+
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    /// Reports an illegal reassignment; for example, an assignment to
+    /// (part of) a non-`mut` local that occurs potentially after that
+    /// local has already been initialized. `place` is the path being
+    /// assigned; `err_place` is a place providing a reason why
+    /// `place` is not mutable (e.g., the non-`mut` local `x` in an
+    /// assignment to `x.f`).
+    pub(in crate::borrow_check) fn report_illegal_reassignment(
+        &mut self,
+        _location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        assigned_span: Span,
+        err_place: &Place<'tcx>,
+    ) {
+        let (from_arg, local_decl, local_name) = match err_place.as_local() {
+            Some(local) => (
+                self.body.local_kind(local) == LocalKind::Arg,
+                Some(&self.body.local_decls[local]),
+                self.local_names[local],
+            ),
+            None => (false, None, None),
+        };
+
+        // If root local is initialized immediately (everything apart from let
+        // PATTERN;) then make the error refer to that local, rather than the
+        // place being assigned later.
+        let (place_description, assigned_span) = match local_decl {
+            Some(LocalDecl {
+                local_info: LocalInfo::User(ClearCrossCrate::Clear),
+                ..
+            })
+            | Some(LocalDecl {
+                local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                    opt_match_place: None,
+                    ..
+                }))),
+                ..
+            })
+            | Some(LocalDecl {
+                local_info: LocalInfo::StaticRef { .. },
+                ..
+            })
+            | Some(LocalDecl {
+                local_info: LocalInfo::Other,
+                ..
+            })
+            | None => (self.describe_place(place.as_ref()), assigned_span),
+            Some(decl) => (self.describe_place(err_place.as_ref()), decl.source_info.span),
+        };
+
+        let mut err = self.cannot_reassign_immutable(
+            span,
+            place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
+            from_arg,
+        );
+        let msg = if from_arg {
+            "cannot assign to immutable argument"
+        } else {
+            "cannot assign twice to immutable variable"
+        };
+        if span != assigned_span {
+            if !from_arg {
+                let value_msg = match place_description {
+                    Some(name) => format!("`{}`", name),
+                    None => "value".to_owned(),
+                };
+                err.span_label(assigned_span, format!("first assignment to {}", value_msg));
+            }
+        }
+        if let Some(decl) = local_decl {
+            if let Some(name) = local_name {
+                if decl.can_be_made_mutable() {
+                    err.span_suggestion(
+                        decl.source_info.span,
+                        "make this binding mutable",
+                        format!("mut {}", name),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        }
+        err.span_label(span, msg);
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
+        let tcx = self.infcx.tcx;
+        match place.projection {
+            [] => {
+                StorageDeadOrDrop::LocalStorageDead
+            }
+            [proj_base @ .., elem] => {
+                // FIXME(spastorino) make this iterate
+                let base_access = self.classify_drop_access_kind(PlaceRef {
+                    base: place.base,
+                    projection: proj_base,
+                });
+                match elem {
+                    ProjectionElem::Deref => match base_access {
+                        StorageDeadOrDrop::LocalStorageDead
+                        | StorageDeadOrDrop::BoxedStorageDead => {
+                            assert!(
+                                Place::ty_from(
+                                    &place.base,
+                                    proj_base,
+                                    *self.body,
+                                    tcx
+                                ).ty.is_box(),
+                                "Drop of value behind a reference or raw pointer"
+                            );
+                            StorageDeadOrDrop::BoxedStorageDead
+                        }
+                        StorageDeadOrDrop::Destructor(_) => base_access,
+                    },
+                    ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
+                        let base_ty = Place::ty_from(
+                            &place.base,
+                            proj_base,
+                            *self.body,
+                            tcx
+                        ).ty;
+                        match base_ty.kind {
+                            ty::Adt(def, _) if def.has_dtor(tcx) => {
+                                // Report the outermost adt with a destructor
+                                match base_access {
+                                    StorageDeadOrDrop::Destructor(_) => base_access,
+                                    StorageDeadOrDrop::LocalStorageDead
+                                    | StorageDeadOrDrop::BoxedStorageDead => {
+                                        StorageDeadOrDrop::Destructor(base_ty)
+                                    }
+                                }
+                            }
+                            _ => base_access,
+                        }
+                    }
+
+                    ProjectionElem::ConstantIndex { .. }
+                    | ProjectionElem::Subslice { .. }
+                    | ProjectionElem::Index(_) => base_access,
+                }
+            }
+        }
+    }
+
+    /// Describe the reason for the fake borrow that was assigned to `place`.
+    fn classify_immutable_section(&self, place: &Place<'tcx>) -> Option<&'static str> {
+        use rustc::mir::visit::Visitor;
+        struct FakeReadCauseFinder<'a, 'tcx> {
+            place: &'a Place<'tcx>,
+            cause: Option<FakeReadCause>,
+        }
+        impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'_, 'tcx> {
+            fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
+                match statement {
+                    Statement {
+                        kind: StatementKind::FakeRead(cause, box ref place),
+                        ..
+                    } if *place == *self.place => {
+                        self.cause = Some(*cause);
+                    }
+                    _ => (),
+                }
+            }
+        }
+        let mut visitor = FakeReadCauseFinder { place, cause: None };
+        visitor.visit_body(self.body);
+        match visitor.cause {
+            Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
+            Some(FakeReadCause::ForIndex) => Some("indexing expression"),
+            _ => None,
+        }
+    }
+
+    /// Annotate argument and return type of function and closure with (synthesized) lifetime for
+    /// borrow of local value that does not live long enough.
+    fn annotate_argument_and_return_for_borrow(
+        &self,
+        borrow: &BorrowData<'tcx>,
+    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
+        // Define a fallback for when we can't match a closure.
+        let fallback = || {
+            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
+            if is_closure {
+                None
+            } else {
+                let ty = self.infcx.tcx.type_of(self.mir_def_id);
+                match ty.kind {
+                    ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
+                        self.mir_def_id,
+                        self.infcx.tcx.fn_sig(self.mir_def_id),
+                    ),
+                    _ => None,
+                }
+            }
+        };
+
+        // In order to determine whether we need to annotate, we need to check whether the reserve
+        // place was an assignment into a temporary.
+        //
+        // If it was, we check whether or not that temporary is eventually assigned into the return
+        // place. If it was, we can add annotations about the function's return type and arguments
+        // and it'll make sense.
+        let location = borrow.reserve_location;
+        debug!(
+            "annotate_argument_and_return_for_borrow: location={:?}",
+            location
+        );
+        if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
+             = &self.body[location.block].statements.get(location.statement_index)
+        {
+            debug!(
+                "annotate_argument_and_return_for_borrow: reservation={:?}",
+                reservation
+            );
+            // Check that the initial assignment of the reserve location is into a temporary.
+            let mut target = match reservation.as_local() {
+                Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
+                _ => return None,
+            };
+
+            // Next, look through the rest of the block, checking if we are assigning the
+            // `target` (that is, the place that contains our borrow) to anything.
+            let mut annotated_closure = None;
+            for stmt in &self.body[location.block].statements[location.statement_index + 1..]
+            {
+                debug!(
+                    "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
+                    target, stmt
+                );
+                if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
+                    if let Some(assigned_to) = place.as_local() {
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: assigned_to={:?} \
+                             rvalue={:?}",
+                            assigned_to, rvalue
+                        );
+                        // Check if our `target` was captured by a closure.
+                        if let Rvalue::Aggregate(
+                            box AggregateKind::Closure(def_id, substs),
+                            operands,
+                        ) = rvalue
+                        {
+                            for operand in operands {
+                                let assigned_from = match operand {
+                                    Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                        assigned_from
+                                    }
+                                    _ => continue,
+                                };
+                                debug!(
+                                    "annotate_argument_and_return_for_borrow: assigned_from={:?}",
+                                    assigned_from
+                                );
+
+                                // Find the local from the operand.
+                                let assigned_from_local = match assigned_from.local_or_deref_local()
+                                {
+                                    Some(local) => local,
+                                    None => continue,
+                                };
+
+                                if assigned_from_local != target {
+                                    continue;
+                                }
+
+                                // If a closure captured our `target` and then assigned
+                                // into a place then we should annotate the closure in
+                                // case it ends up being assigned into the return place.
+                                annotated_closure = self.annotate_fn_sig(
+                                    *def_id,
+                                    self.infcx.closure_sig(*def_id, *substs),
+                                );
+                                debug!(
+                                    "annotate_argument_and_return_for_borrow: \
+                                     annotated_closure={:?} assigned_from_local={:?} \
+                                     assigned_to={:?}",
+                                    annotated_closure, assigned_from_local, assigned_to
+                                );
+
+                                if assigned_to == mir::RETURN_PLACE {
+                                    // If it was assigned directly into the return place, then
+                                    // return now.
+                                    return annotated_closure;
+                                } else {
+                                    // Otherwise, update the target.
+                                    target = assigned_to;
+                                }
+                            }
+
+                            // If none of our closure's operands matched, then skip to the next
+                            // statement.
+                            continue;
+                        }
+
+                        // Otherwise, look at other types of assignment.
+                        let assigned_from = match rvalue {
+                            Rvalue::Ref(_, _, assigned_from) => assigned_from,
+                            Rvalue::Use(operand) => match operand {
+                                Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                    assigned_from
+                                }
+                                _ => continue,
+                            },
+                            _ => continue,
+                        };
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: \
+                             assigned_from={:?}",
+                            assigned_from,
+                        );
+
+                        // Find the local from the rvalue.
+                        let assigned_from_local = match assigned_from.local_or_deref_local() {
+                            Some(local) => local,
+                            None => continue,
+                        };
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: \
+                             assigned_from_local={:?}",
+                            assigned_from_local,
+                        );
+
+                        // Check if our local matches the target - if so, we've assigned our
+                        // borrow to a new place.
+                        if assigned_from_local != target {
+                            continue;
+                        }
+
+                        // If we assigned our `target` into a new place, then we should
+                        // check if it was the return place.
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: \
+                             assigned_from_local={:?} assigned_to={:?}",
+                            assigned_from_local, assigned_to
+                        );
+                        if assigned_to == mir::RETURN_PLACE {
+                            // If it was then return the annotated closure if there was one,
+                            // else, annotate this function.
+                            return annotated_closure.or_else(fallback);
+                        }
+
+                        // If we didn't assign into the return place, then we just update
+                        // the target.
+                        target = assigned_to;
+                    }
+                }
+            }
+
+            // Check the terminator if we didn't find anything in the statements.
+            let terminator = &self.body[location.block].terminator();
+            debug!(
+                "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
+                target, terminator
+            );
+            if let TerminatorKind::Call {
+                destination: Some((place, _)),
+                args,
+                ..
+            } = &terminator.kind
+            {
+                if let Some(assigned_to) = place.as_local() {
+                    debug!(
+                        "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
+                        assigned_to, args
+                    );
+                    for operand in args {
+                        let assigned_from = match operand {
+                            Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                assigned_from
+                            }
+                            _ => continue,
+                        };
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: assigned_from={:?}",
+                            assigned_from,
+                        );
+
+                        if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
+                            debug!(
+                                "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
+                                assigned_from_local,
+                            );
+
+                            if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
+                                return annotated_closure.or_else(fallback);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // If we haven't found an assignment into the return place, then we need not add
+        // any annotations.
+        debug!("annotate_argument_and_return_for_borrow: none found");
+        None
+    }
+
+    /// Annotate the first argument and return type of a function signature if they are
+    /// references.
+    fn annotate_fn_sig(
+        &self,
+        did: DefId,
+        sig: ty::PolyFnSig<'tcx>,
+    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
+        debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
+        let is_closure = self.infcx.tcx.is_closure(did);
+        let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(did)?;
+        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
+
+        // We need to work out which arguments to highlight. We do this by looking
+        // at the return type, where there are three cases:
+        //
+        // 1. If there are named arguments, then we should highlight the return type and
+        //    highlight any of the arguments that are also references with that lifetime.
+        //    If there are no arguments that have the same lifetime as the return type,
+        //    then don't highlight anything.
+        // 2. The return type is a reference with an anonymous lifetime. If this is
+        //    the case, then we can take advantage of (and teach) the lifetime elision
+        //    rules.
+        //
+        //    We know that an error is being reported. So the arguments and return type
+        //    must satisfy the elision rules. Therefore, if there is a single argument
+        //    then that means the return type and first (and only) argument have the same
+        //    lifetime and the borrow isn't meeting that, we can highlight the argument
+        //    and return type.
+        //
+        //    If there are multiple arguments then the first argument must be self (else
+        //    it would not satisfy the elision rules), so we can highlight self and the
+        //    return type.
+        // 3. The return type is not a reference. In this case, we don't highlight
+        //    anything.
+        let return_ty = sig.output();
+        match return_ty.skip_binder().kind {
+            ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
+                // This is case 1 from above, return type is a named reference so we need to
+                // search for relevant arguments.
+                let mut arguments = Vec::new();
+                for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
+                    if let ty::Ref(argument_region, _, _) = argument.kind {
+                        if argument_region == return_region {
+                            // Need to use the `rustc::ty` types to compare against the
+                            // `return_region`. Then use the `rustc::hir` type to get only
+                            // the lifetime span.
+                            if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
+                                // With access to the lifetime, we can get
+                                // the span of it.
+                                arguments.push((*argument, lifetime.span));
+                            } else {
+                                bug!("ty type is a ref but hir type is not");
+                            }
+                        }
+                    }
+                }
+
+                // We need to have arguments. This shouldn't happen, but it's worth checking.
+                if arguments.is_empty() {
+                    return None;
+                }
+
+                // We use a mix of the HIR and the Ty types to get information
+                // as the HIR doesn't have full types for closure arguments.
+                let return_ty = *sig.output().skip_binder();
+                let mut return_span = fn_decl.output.span();
+                if let hir::FunctionRetTy::Return(ty) = &fn_decl.output {
+                    if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
+                        return_span = lifetime.span;
+                    }
+                }
+
+                Some(AnnotatedBorrowFnSignature::NamedFunction {
+                    arguments,
+                    return_ty,
+                    return_span,
+                })
+            }
+            ty::Ref(_, _, _) if is_closure => {
+                // This is case 2 from above but only for closures, return type is anonymous
+                // reference so we select
+                // the first argument.
+                let argument_span = fn_decl.inputs.first()?.span;
+                let argument_ty = sig.inputs().skip_binder().first()?;
+
+                // Closure arguments are wrapped in a tuple, so we need to get the first
+                // from that.
+                if let ty::Tuple(elems) = argument_ty.kind {
+                    let argument_ty = elems.first()?.expect_ty();
+                    if let ty::Ref(_, _, _) = argument_ty.kind {
+                        return Some(AnnotatedBorrowFnSignature::Closure {
+                            argument_ty,
+                            argument_span,
+                        });
+                    }
+                }
+
+                None
+            }
+            ty::Ref(_, _, _) => {
+                // This is also case 2 from above but for functions, return type is still an
+                // anonymous reference so we select the first argument.
+                let argument_span = fn_decl.inputs.first()?.span;
+                let argument_ty = sig.inputs().skip_binder().first()?;
+
+                let return_span = fn_decl.output.span();
+                let return_ty = *sig.output().skip_binder();
+
+                // We expect the first argument to be a reference.
+                match argument_ty.kind {
+                    ty::Ref(_, _, _) => {}
+                    _ => return None,
+                }
+
+                Some(AnnotatedBorrowFnSignature::AnonymousFunction {
+                    argument_ty,
+                    argument_span,
+                    return_ty,
+                    return_span,
+                })
+            }
+            _ => {
+                // This is case 3 from above, return type is not a reference so don't highlight
+                // anything.
+                None
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+enum AnnotatedBorrowFnSignature<'tcx> {
+    NamedFunction {
+        arguments: Vec<(Ty<'tcx>, Span)>,
+        return_ty: Ty<'tcx>,
+        return_span: Span,
+    },
+    AnonymousFunction {
+        argument_ty: Ty<'tcx>,
+        argument_span: Span,
+        return_ty: Ty<'tcx>,
+        return_span: Span,
+    },
+    Closure {
+        argument_ty: Ty<'tcx>,
+        argument_span: Span,
+    },
+}
+
+impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
+    /// Annotate the provided diagnostic with information about borrow from the fn signature that
+    /// helps explain.
+    pub(in crate::borrow_check) fn emit(
+        &self,
+        cx: &mut MirBorrowckCtxt<'_, 'tcx>,
+        diag: &mut DiagnosticBuilder<'_>,
+    ) -> String {
+        match self {
+            AnnotatedBorrowFnSignature::Closure {
+                argument_ty,
+                argument_span,
+            } => {
+                diag.span_label(
+                    *argument_span,
+                    format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
+                );
+
+                cx.get_region_name_for_ty(argument_ty, 0)
+            }
+            AnnotatedBorrowFnSignature::AnonymousFunction {
+                argument_ty,
+                argument_span,
+                return_ty,
+                return_span,
+            } => {
+                let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
+                diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
+
+                let return_ty_name = cx.get_name_for_ty(return_ty, 0);
+                let types_equal = return_ty_name == argument_ty_name;
+                diag.span_label(
+                    *return_span,
+                    format!(
+                        "{}has type `{}`",
+                        if types_equal { "also " } else { "" },
+                        return_ty_name,
+                    ),
+                );
+
+                diag.note(
+                    "argument and return type have the same lifetime due to lifetime elision rules",
+                );
+                diag.note(
+                    "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
+                     lifetime-syntax.html#lifetime-elision>",
+                );
+
+                cx.get_region_name_for_ty(return_ty, 0)
+            }
+            AnnotatedBorrowFnSignature::NamedFunction {
+                arguments,
+                return_ty,
+                return_span,
+            } => {
+                // Region of return type and arguments checked to be the same earlier.
+                let region_name = cx.get_region_name_for_ty(return_ty, 0);
+                for (_, argument_span) in arguments {
+                    diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
+                }
+
+                diag.span_label(
+                    *return_span,
+                    format!("also has lifetime `{}`", region_name,),
+                );
+
+                diag.help(&format!(
+                    "use data from the highlighted arguments which match the `{}` lifetime of \
+                     the return type",
+                    region_name,
+                ));
+
+                region_name
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
new file mode 100644 (file)
index 0000000..67c3c36
--- /dev/null
@@ -0,0 +1,668 @@
+use std::collections::VecDeque;
+
+use crate::borrow_check::borrow_set::BorrowData;
+use crate::borrow_check::nll::region_infer::Cause;
+use crate::borrow_check::nll::ConstraintDescription;
+use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
+use rustc::mir::{
+    CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
+    Statement, StatementKind, TerminatorKind,
+};
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::adjustment::{PointerCast};
+use rustc_index::vec::IndexVec;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::DiagnosticBuilder;
+use syntax_pos::Span;
+use syntax_pos::symbol::Symbol;
+
+use super::{UseSpans, find_use, RegionName};
+
+#[derive(Debug)]
+pub(in crate::borrow_check) enum BorrowExplanation {
+    UsedLater(LaterUseKind, Span),
+    UsedLaterInLoop(LaterUseKind, Span),
+    UsedLaterWhenDropped {
+        drop_loc: Location,
+        dropped_local: Local,
+        should_note_order: bool,
+    },
+    MustBeValidFor {
+        category: ConstraintCategory,
+        from_closure: bool,
+        span: Span,
+        region_name: RegionName,
+        opt_place_desc: Option<String>,
+    },
+    Unexplained,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub(in crate::borrow_check) enum LaterUseKind {
+    TraitCapture,
+    ClosureCapture,
+    Call,
+    FakeLetRead,
+    Other,
+}
+
+impl BorrowExplanation {
+    pub(in crate::borrow_check) fn is_explained(&self) -> bool {
+        match self {
+            BorrowExplanation::Unexplained => false,
+            _ => true,
+        }
+    }
+    pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        body: &Body<'tcx>,
+        local_names: &IndexVec<Local, Option<Symbol>>,
+        err: &mut DiagnosticBuilder<'_>,
+        borrow_desc: &str,
+        borrow_span: Option<Span>,
+    ) {
+        match *self {
+            BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
+                let message = match later_use_kind {
+                    LaterUseKind::TraitCapture => "captured here by trait object",
+                    LaterUseKind::ClosureCapture => "captured here by closure",
+                    LaterUseKind::Call => "used by call",
+                    LaterUseKind::FakeLetRead => "stored here",
+                    LaterUseKind::Other => "used here",
+                };
+                if !borrow_span.map(|sp| sp.overlaps(var_or_use_span)).unwrap_or(false) {
+                    err.span_label(
+                        var_or_use_span,
+                        format!("{}borrow later {}", borrow_desc, message),
+                    );
+                }
+            }
+            BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
+                let message = match later_use_kind {
+                    LaterUseKind::TraitCapture => {
+                        "borrow captured here by trait object, in later iteration of loop"
+                    }
+                    LaterUseKind::ClosureCapture => {
+                        "borrow captured here by closure, in later iteration of loop"
+                    }
+                    LaterUseKind::Call => "borrow used by call, in later iteration of loop",
+                    LaterUseKind::FakeLetRead => "borrow later stored here",
+                    LaterUseKind::Other => "borrow used here, in later iteration of loop",
+                };
+                err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+            }
+            BorrowExplanation::UsedLaterWhenDropped {
+                drop_loc,
+                dropped_local,
+                should_note_order,
+            } => {
+                let local_decl = &body.local_decls[dropped_local];
+                let (dtor_desc, type_desc) = match local_decl.ty.kind {
+                    // If type is an ADT that implements Drop, then
+                    // simplify output by reporting just the ADT name.
+                    ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => (
+                        "`Drop` code",
+                        format!("type `{}`", tcx.def_path_str(adt.did)),
+                    ),
+
+                    // Otherwise, just report the whole type (and use
+                    // the intentionally fuzzy phrase "destructor")
+                    ty::Closure(..) => ("destructor", "closure".to_owned()),
+                    ty::Generator(..) => ("destructor", "generator".to_owned()),
+
+                    _ => ("destructor", format!("type `{}`", local_decl.ty)),
+                };
+
+                match local_names[dropped_local] {
+                    Some(local_name) if !local_decl.from_compiler_desugaring() => {
+                        let message = format!(
+                            "{B}borrow might be used here, when `{LOC}` is dropped \
+                             and runs the {DTOR} for {TYPE}",
+                            B = borrow_desc,
+                            LOC = local_name,
+                            TYPE = type_desc,
+                            DTOR = dtor_desc
+                        );
+                        err.span_label(body.source_info(drop_loc).span, message);
+
+                        if should_note_order {
+                            err.note(
+                                "values in a scope are dropped \
+                                 in the opposite order they are defined",
+                            );
+                        }
+                    }
+                    _ => {
+                        err.span_label(
+                            local_decl.source_info.span,
+                            format!(
+                                "a temporary with access to the {B}borrow \
+                                 is created here ...",
+                                B = borrow_desc
+                            ),
+                        );
+                        let message = format!(
+                            "... and the {B}borrow might be used here, \
+                             when that temporary is dropped \
+                             and runs the {DTOR} for {TYPE}",
+                            B = borrow_desc,
+                            TYPE = type_desc,
+                            DTOR = dtor_desc
+                        );
+                        err.span_label(body.source_info(drop_loc).span, message);
+
+                        if let Some(info) = &local_decl.is_block_tail {
+                            // FIXME: use span_suggestion instead, highlighting the
+                            // whole block tail expression.
+                            let msg = if info.tail_result_is_ignored {
+                                "The temporary is part of an expression at the end of a block. \
+                                 Consider adding semicolon after the expression so its temporaries \
+                                 are dropped sooner, before the local variables declared by the \
+                                 block are dropped."
+                            } else {
+                                "The temporary is part of an expression at the end of a block. \
+                                 Consider forcing this temporary to be dropped sooner, before \
+                                 the block's local variables are dropped. \
+                                 For example, you could save the expression's value in a new \
+                                 local variable `x` and then make `x` be the expression \
+                                 at the end of the block."
+                            };
+
+                            err.note(msg);
+                        }
+                    }
+                }
+            }
+            BorrowExplanation::MustBeValidFor {
+                category,
+                span,
+                ref region_name,
+                ref opt_place_desc,
+                from_closure: _,
+            } => {
+                region_name.highlight_region_name(err);
+
+                if let Some(desc) = opt_place_desc {
+                    err.span_label(
+                        span,
+                        format!(
+                            "{}requires that `{}` is borrowed for `{}`",
+                            category.description(),
+                            desc,
+                            region_name,
+                        ),
+                    );
+                } else {
+                    err.span_label(
+                        span,
+                        format!(
+                            "{}requires that {}borrow lasts for `{}`",
+                            category.description(),
+                            borrow_desc,
+                            region_name,
+                        ),
+                    );
+                };
+            }
+            _ => {}
+        }
+    }
+}
+
+impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+    /// Returns structured explanation for *why* the borrow contains the
+    /// point from `location`. This is key for the "3-point errors"
+    /// [described in the NLL RFC][d].
+    ///
+    /// # Parameters
+    ///
+    /// - `borrow`: the borrow in question
+    /// - `location`: where the borrow occurs
+    /// - `kind_place`: if Some, this describes the statement that triggered the error.
+    ///   - first half is the kind of write, if any, being performed
+    ///   - second half is the place being accessed
+    ///
+    /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
+    pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
+        &self,
+        location: Location,
+        borrow: &BorrowData<'tcx>,
+        kind_place: Option<(WriteKind, &Place<'tcx>)>,
+    ) -> BorrowExplanation {
+        debug!(
+            "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
+            location, borrow, kind_place
+        );
+
+        let regioncx = &self.nonlexical_regioncx;
+        let body: &Body<'_> = &self.body;
+        let tcx = self.infcx.tcx;
+
+        let borrow_region_vid = borrow.region;
+        debug!(
+            "explain_why_borrow_contains_point: borrow_region_vid={:?}",
+            borrow_region_vid
+        );
+
+        let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, location);
+        debug!(
+            "explain_why_borrow_contains_point: region_sub={:?}",
+            region_sub
+        );
+
+        match find_use::find(body, regioncx, tcx, region_sub, location) {
+            Some(Cause::LiveVar(local, location)) => {
+                let span = body.source_info(location).span;
+                let spans = self
+                    .move_spans(Place::from(local).as_ref(), location)
+                    .or_else(|| self.borrow_spans(span, location));
+
+                let borrow_location = location;
+                if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
+                    let later_use = self.later_use_kind(borrow, spans, location);
+                    BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
+                } else {
+                    // Check if the location represents a `FakeRead`, and adapt the error
+                    // message to the `FakeReadCause` it is from: in particular,
+                    // the ones inserted in optimized `let var = <expr>` patterns.
+                    let later_use = self.later_use_kind(borrow, spans, location);
+                    BorrowExplanation::UsedLater(later_use.0, later_use.1)
+                }
+            }
+
+            Some(Cause::DropVar(local, location)) => {
+                let mut should_note_order = false;
+                if self.local_names[local].is_some() {
+                    if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
+                        if let Some(borrowed_local) = place.as_local() {
+                            if self.local_names[borrowed_local].is_some()
+                                && local != borrowed_local
+                            {
+                                should_note_order = true;
+                            }
+                        }
+                    }
+                }
+
+                BorrowExplanation::UsedLaterWhenDropped {
+                    drop_loc: location,
+                    dropped_local: local,
+                    should_note_order,
+                }
+            }
+
+            None => {
+                if let Some(region) = regioncx.to_error_region_vid(borrow_region_vid) {
+                    let (category, from_closure, span, region_name) =
+                        self.nonlexical_regioncx.free_region_constraint_info(
+                            &self.body,
+                            &self.local_names,
+                            &self.upvars,
+                            self.mir_def_id,
+                            self.infcx,
+                            borrow_region_vid,
+                            region,
+                        );
+                    if let Some(region_name) = region_name {
+                        let opt_place_desc =
+                            self.describe_place(borrow.borrowed_place.as_ref());
+                        BorrowExplanation::MustBeValidFor {
+                            category,
+                            from_closure,
+                            span,
+                            region_name,
+                            opt_place_desc,
+                        }
+                    } else {
+                        debug!("explain_why_borrow_contains_point: \
+                                Could not generate a region name");
+                        BorrowExplanation::Unexplained
+                    }
+                } else {
+                    debug!("explain_why_borrow_contains_point: \
+                            Could not generate an error region vid");
+                    BorrowExplanation::Unexplained
+                }
+            }
+        }
+    }
+
+    /// true if `borrow_location` can reach `use_location` by going through a loop and
+    /// `use_location` is also inside of that loop
+    fn is_use_in_later_iteration_of_loop(
+        &self,
+        borrow_location: Location,
+        use_location: Location,
+    ) -> bool {
+        let back_edge = self.reach_through_backedge(borrow_location, use_location);
+        back_edge.map_or(false, |back_edge| {
+            self.can_reach_head_of_loop(use_location, back_edge)
+        })
+    }
+
+    /// Returns the outmost back edge if `from` location can reach `to` location passing through
+    /// that back edge
+    fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> {
+        let mut visited_locations = FxHashSet::default();
+        let mut pending_locations = VecDeque::new();
+        visited_locations.insert(from);
+        pending_locations.push_back(from);
+        debug!("reach_through_backedge: from={:?} to={:?}", from, to,);
+
+        let mut outmost_back_edge = None;
+        while let Some(location) = pending_locations.pop_front() {
+            debug!(
+                "reach_through_backedge: location={:?} outmost_back_edge={:?}
+                   pending_locations={:?} visited_locations={:?}",
+                location, outmost_back_edge, pending_locations, visited_locations
+            );
+
+            if location == to && outmost_back_edge.is_some() {
+                // We've managed to reach the use location
+                debug!("reach_through_backedge: found!");
+                return outmost_back_edge;
+            }
+
+            let block = &self.body.basic_blocks()[location.block];
+
+            if location.statement_index < block.statements.len() {
+                let successor = location.successor_within_block();
+                if visited_locations.insert(successor) {
+                    pending_locations.push_back(successor);
+                }
+            } else {
+                pending_locations.extend(
+                    block
+                        .terminator()
+                        .successors()
+                        .map(|bb| Location {
+                            statement_index: 0,
+                            block: *bb,
+                        })
+                        .filter(|s| visited_locations.insert(*s))
+                        .map(|s| {
+                            if self.is_back_edge(location, s) {
+                                match outmost_back_edge {
+                                    None => {
+                                        outmost_back_edge = Some(location);
+                                    }
+
+                                    Some(back_edge)
+                                        if location.dominates(back_edge, &self.dominators) =>
+                                    {
+                                        outmost_back_edge = Some(location);
+                                    }
+
+                                    Some(_) => {}
+                                }
+                            }
+
+                            s
+                        }),
+                );
+            }
+        }
+
+        None
+    }
+
+    /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the
+    /// intermediate nodes
+    fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool {
+        self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default())
+    }
+
+    fn find_loop_head_dfs(
+        &self,
+        from: Location,
+        loop_head: Location,
+        visited_locations: &mut FxHashSet<Location>,
+    ) -> bool {
+        visited_locations.insert(from);
+
+        if from == loop_head {
+            return true;
+        }
+
+        if loop_head.dominates(from, &self.dominators) {
+            let block = &self.body.basic_blocks()[from.block];
+
+            if from.statement_index < block.statements.len() {
+                let successor = from.successor_within_block();
+
+                if !visited_locations.contains(&successor)
+                    && self.find_loop_head_dfs(successor, loop_head, visited_locations)
+                {
+                    return true;
+                }
+            } else {
+                for bb in block.terminator().successors() {
+                    let successor = Location {
+                        statement_index: 0,
+                        block: *bb,
+                    };
+
+                    if !visited_locations.contains(&successor)
+                        && self.find_loop_head_dfs(successor, loop_head, visited_locations)
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        false
+    }
+
+    /// True if an edge `source -> target` is a backedge -- in other words, if the target
+    /// dominates the source.
+    fn is_back_edge(&self, source: Location, target: Location) -> bool {
+        target.dominates(source, &self.dominators)
+    }
+
+    /// Determine how the borrow was later used.
+    fn later_use_kind(
+        &self,
+        borrow: &BorrowData<'tcx>,
+        use_spans: UseSpans,
+        location: Location,
+    ) -> (LaterUseKind, Span) {
+        match use_spans {
+            UseSpans::ClosureUse { var_span, .. } => {
+                // Used in a closure.
+                (LaterUseKind::ClosureCapture, var_span)
+            }
+            UseSpans::OtherUse(span) => {
+                let block = &self.body.basic_blocks()[location.block];
+
+                let kind = if let Some(&Statement {
+                    kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
+                    ..
+                }) = block.statements.get(location.statement_index)
+                {
+                    LaterUseKind::FakeLetRead
+                } else if self.was_captured_by_trait_object(borrow) {
+                    LaterUseKind::TraitCapture
+                } else if location.statement_index == block.statements.len() {
+                    if let TerminatorKind::Call {
+                        ref func,
+                        from_hir_call: true,
+                        ..
+                    } = block.terminator().kind
+                    {
+                        // Just point to the function, to reduce the chance of overlapping spans.
+                        let function_span = match func {
+                            Operand::Constant(c) => c.span,
+                            Operand::Copy(place) |
+                            Operand::Move(place) => {
+                                if let Some(l) = place.as_local() {
+                                    let local_decl = &self.body.local_decls[l];
+                                    if self.local_names[l].is_none() {
+                                        local_decl.source_info.span
+                                    } else {
+                                        span
+                                    }
+                                } else {
+                                    span
+                                }
+                            }
+                        };
+                        return (LaterUseKind::Call, function_span);
+                    } else {
+                        LaterUseKind::Other
+                    }
+                } else {
+                    LaterUseKind::Other
+                };
+
+                (kind, span)
+            }
+        }
+    }
+
+    /// Checks if a borrowed value was captured by a trait object. We do this by
+    /// looking forward in the MIR from the reserve location and checking if we see
+    /// a unsized cast to a trait object on our data.
+    fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
+        // Start at the reserve location, find the place that we want to see cast to a trait object.
+        let location = borrow.reserve_location;
+        let block = &self.body[location.block];
+        let stmt = block.statements.get(location.statement_index);
+        debug!(
+            "was_captured_by_trait_object: location={:?} stmt={:?}",
+            location, stmt
+        );
+
+        // We make a `queue` vector that has the locations we want to visit. As of writing, this
+        // will only ever have one item at any given time, but by using a vector, we can pop from
+        // it which simplifies the termination logic.
+        let mut queue = vec![location];
+        let mut target = if let Some(&Statement {
+            kind: StatementKind::Assign(box(ref place, _)),
+            ..
+        }) = stmt {
+            if let Some(local) = place.as_local() {
+                local
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        };
+
+        debug!(
+            "was_captured_by_trait: target={:?} queue={:?}",
+            target, queue
+        );
+        while let Some(current_location) = queue.pop() {
+            debug!("was_captured_by_trait: target={:?}", target);
+            let block = &self.body[current_location.block];
+            // We need to check the current location to find out if it is a terminator.
+            let is_terminator = current_location.statement_index == block.statements.len();
+            if !is_terminator {
+                let stmt = &block.statements[current_location.statement_index];
+                debug!("was_captured_by_trait_object: stmt={:?}", stmt);
+
+                // The only kind of statement that we care about is assignments...
+                if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
+                    let into = match place.local_or_deref_local() {
+                        Some(into) => into,
+                        None => {
+                            // Continue at the next location.
+                            queue.push(current_location.successor_within_block());
+                            continue;
+                        }
+                    };
+
+                    match rvalue {
+                        // If we see a use, we should check whether it is our data, and if so
+                        // update the place that we're looking for to that new place.
+                        Rvalue::Use(operand) => match operand {
+                            Operand::Copy(place)
+                            | Operand::Move(place) => {
+                                if let Some(from) = place.as_local() {
+                                    if from == target {
+                                        target = into;
+                                    }
+                                }
+                            }
+                            _ => {}
+                        },
+                        // If we see a unsized cast, then if it is our data we should check
+                        // whether it is being cast to a trait object.
+                        Rvalue::Cast(
+                            CastKind::Pointer(PointerCast::Unsize), operand, ty
+                        ) => match operand {
+                            Operand::Copy(place)
+                            | Operand::Move(place) => {
+                                if let Some(from) = place.as_local() {
+                                    if from == target {
+                                        debug!("was_captured_by_trait_object: ty={:?}", ty);
+                                        // Check the type for a trait object.
+                                        return match ty.kind {
+                                            // `&dyn Trait`
+                                            ty::Ref(_, ty, _) if ty.is_trait() => true,
+                                            // `Box<dyn Trait>`
+                                            _ if ty.is_box() && ty.boxed_ty().is_trait() => true,
+                                            // `dyn Trait`
+                                            _ if ty.is_trait() => true,
+                                            // Anything else.
+                                            _ => false,
+                                        };
+                                    }
+                                }
+                                return false;
+                            }
+                            _ => return false,
+                        },
+                        _ => {}
+                    }
+                }
+
+                // Continue at the next location.
+                queue.push(current_location.successor_within_block());
+            } else {
+                // The only thing we need to do for terminators is progress to the next block.
+                let terminator = block.terminator();
+                debug!("was_captured_by_trait_object: terminator={:?}", terminator);
+
+                if let TerminatorKind::Call {
+                    destination: Some((place, block)),
+                    args,
+                    ..
+                } = &terminator.kind {
+                    if let Some(dest) = place.as_local() {
+                        debug!(
+                            "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
+                            target, dest, args
+                        );
+                        // Check if one of the arguments to this function is the target place.
+                        let found_target = args.iter().any(|arg| {
+                            if let Operand::Move(place) = arg {
+                                if let Some(potential) = place.as_local() {
+                                    potential == target
+                                } else {
+                                    false
+                                }
+                            } else {
+                                false
+                            }
+                        });
+
+                        // If it is, follow this to the next block and update the target.
+                        if found_target {
+                            target = dest;
+                            queue.push(block.start_location());
+                        }
+                    }
+                }
+            }
+
+            debug!("was_captured_by_trait: queue={:?}", queue);
+        }
+
+        // We didn't find anything and ran out of locations to check.
+        false
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/find_use.rs b/src/librustc_mir/borrow_check/diagnostics/find_use.rs
new file mode 100644 (file)
index 0000000..7ab0692
--- /dev/null
@@ -0,0 +1,135 @@
+use std::collections::VecDeque;
+use std::rc::Rc;
+
+use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
+use crate::borrow_check::nll::ToRegionVid;
+use crate::util::liveness::{self, DefUse};
+use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
+use rustc::mir::{Local, Location, Body};
+use rustc::ty::{RegionVid, TyCtxt};
+use rustc_data_structures::fx::FxHashSet;
+
+crate fn find<'tcx>(
+    body: &Body<'tcx>,
+    regioncx: &Rc<RegionInferenceContext<'tcx>>,
+    tcx: TyCtxt<'tcx>,
+    region_vid: RegionVid,
+    start_point: Location,
+) -> Option<Cause> {
+    let mut uf = UseFinder {
+        body,
+        regioncx,
+        tcx,
+        region_vid,
+        start_point,
+    };
+
+    uf.find()
+}
+
+struct UseFinder<'cx, 'tcx> {
+    body: &'cx Body<'tcx>,
+    regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
+    tcx: TyCtxt<'tcx>,
+    region_vid: RegionVid,
+    start_point: Location,
+}
+
+impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
+    fn find(&mut self) -> Option<Cause> {
+        let mut queue = VecDeque::new();
+        let mut visited = FxHashSet::default();
+
+        queue.push_back(self.start_point);
+        while let Some(p) = queue.pop_front() {
+            if !self.regioncx.region_contains(self.region_vid, p) {
+                continue;
+            }
+
+            if !visited.insert(p) {
+                continue;
+            }
+
+            let block_data = &self.body[p.block];
+
+            match self.def_use(p, block_data.visitable(p.statement_index)) {
+                Some(DefUseResult::Def) => {}
+
+                Some(DefUseResult::UseLive { local }) => {
+                    return Some(Cause::LiveVar(local, p));
+                }
+
+                Some(DefUseResult::UseDrop { local }) => {
+                    return Some(Cause::DropVar(local, p));
+                }
+
+                None => {
+                    if p.statement_index < block_data.statements.len() {
+                        queue.push_back(p.successor_within_block());
+                    } else {
+                        queue.extend(
+                            block_data
+                                .terminator()
+                                .successors()
+                                .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind())
+                                .map(|&bb| Location {
+                                    statement_index: 0,
+                                    block: bb,
+                                }),
+                        );
+                    }
+                }
+            }
+        }
+
+        None
+    }
+
+    fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option<DefUseResult> {
+        let mut visitor = DefUseVisitor {
+            body: self.body,
+            tcx: self.tcx,
+            region_vid: self.region_vid,
+            def_use_result: None,
+        };
+
+        thing.apply(location, &mut visitor);
+
+        visitor.def_use_result
+    }
+}
+
+struct DefUseVisitor<'cx, 'tcx> {
+    body: &'cx Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    region_vid: RegionVid,
+    def_use_result: Option<DefUseResult>,
+}
+
+enum DefUseResult {
+    Def,
+    UseLive { local: Local },
+    UseDrop { local: Local },
+}
+
+impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> {
+    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+        let local_ty = self.body.local_decls[local].ty;
+
+        let mut found_it = false;
+        self.tcx.for_each_free_region(&local_ty, |r| {
+            if r.to_region_vid() == self.region_vid {
+                found_it = true;
+            }
+        });
+
+        if found_it {
+            self.def_use_result = match liveness::categorize(context) {
+                Some(DefUse::Def) => Some(DefUseResult::Def),
+                Some(DefUse::Use) => Some(DefUseResult::UseLive { local }),
+                Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }),
+                None => None,
+            };
+        }
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs
new file mode 100644 (file)
index 0000000..1a76265
--- /dev/null
@@ -0,0 +1,934 @@
+//! Borrow checker diagnostics.
+
+use rustc::hir;
+use rustc::hir::def::Namespace;
+use rustc::hir::def_id::DefId;
+use rustc::hir::GeneratorKind;
+use rustc::mir::{
+    AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand,
+    Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
+    Static, StaticKind, Terminator, TerminatorKind,
+};
+use rustc::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc::ty::layout::VariantIdx;
+use rustc::ty::print::Print;
+use rustc_errors::DiagnosticBuilder;
+use syntax_pos::Span;
+
+use super::borrow_set::BorrowData;
+use super::MirBorrowckCtxt;
+use crate::dataflow::move_paths::{InitLocation, LookupResult};
+
+mod find_use;
+mod var_name;
+mod region_name;
+mod outlives_suggestion;
+
+mod conflict_errors;
+mod move_errors;
+mod mutability_errors;
+mod region_errors;
+mod explain_borrow;
+
+crate use mutability_errors::AccessKind;
+crate use region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
+crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo};
+crate use outlives_suggestion::OutlivesSuggestionBuilder;
+
+pub(super) struct IncludingDowncast(pub(super) bool);
+
+impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+    /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
+    /// is moved after being invoked.
+    ///
+    /// ```text
+    /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
+    ///       its environment
+    ///   --> $DIR/issue-42065.rs:16:29
+    ///    |
+    /// LL |         for (key, value) in dict {
+    ///    |                             ^^^^
+    /// ```
+    pub(super) fn add_moved_or_invoked_closure_note(
+        &self,
+        location: Location,
+        place: PlaceRef<'cx, 'tcx>,
+        diag: &mut DiagnosticBuilder<'_>,
+    ) {
+        debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
+        let mut target = place.local_or_deref_local();
+        for stmt in &self.body[location.block].statements[location.statement_index..] {
+            debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
+            if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
+                debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
+                match from {
+                    Operand::Copy(ref place) |
+                    Operand::Move(ref place) if target == place.local_or_deref_local() =>
+                        target = into.local_or_deref_local(),
+                    _ => {},
+                }
+            }
+        }
+
+        // Check if we are attempting to call a closure after it has been invoked.
+        let terminator = self.body[location.block].terminator();
+        debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
+        if let TerminatorKind::Call {
+            func: Operand::Constant(box Constant {
+                literal: ty::Const {
+                    ty: &ty::TyS { kind: ty::FnDef(id, _), ..  },
+                    ..
+                },
+                ..
+            }),
+            args,
+            ..
+        } = &terminator.kind {
+            debug!("add_moved_or_invoked_closure_note: id={:?}", id);
+            if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
+                let closure = match args.first() {
+                    Some(Operand::Copy(ref place)) |
+                    Some(Operand::Move(ref place)) if target == place.local_or_deref_local() =>
+                        place.local_or_deref_local().unwrap(),
+                    _ => return,
+                };
+
+                debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
+                if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind {
+                    let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
+
+                    if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
+                        .closure_kind_origins()
+                        .get(hir_id)
+                    {
+                        diag.span_note(
+                            *span,
+                            &format!(
+                                "closure cannot be invoked more than once because it moves the \
+                                 variable `{}` out of its environment",
+                                name,
+                            ),
+                        );
+                        return;
+                    }
+                }
+            }
+        }
+
+        // Check if we are just moving a closure after it has been invoked.
+        if let Some(target) = target {
+            if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind {
+                let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
+
+                if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
+                    .closure_kind_origins()
+                    .get(hir_id)
+                {
+                    diag.span_note(
+                        *span,
+                        &format!(
+                            "closure cannot be moved more than once as it is not `Copy` due to \
+                             moving the variable `{}` out of its environment",
+                             name
+                        ),
+                    );
+                }
+            }
+        }
+    }
+
+    /// End-user visible description of `place` if one can be found. If the
+    /// place is a temporary for instance, None will be returned.
+    pub(super) fn describe_place(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option<String> {
+        self.describe_place_with_options(place_ref, IncludingDowncast(false))
+    }
+
+    /// End-user visible description of `place` if one can be found. If the
+    /// place is a temporary for instance, None will be returned.
+    /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
+    /// `Downcast` and `IncludingDowncast` is true
+    pub(super) fn describe_place_with_options(
+        &self,
+        place: PlaceRef<'cx, 'tcx>,
+        including_downcast: IncludingDowncast,
+    ) -> Option<String> {
+        let mut buf = String::new();
+        match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
+            Ok(()) => Some(buf),
+            Err(()) => None,
+        }
+    }
+
+    /// Appends end-user visible description of `place` to `buf`.
+    fn append_place_to_string(
+        &self,
+        place: PlaceRef<'cx, 'tcx>,
+        buf: &mut String,
+        mut autoderef: bool,
+        including_downcast: &IncludingDowncast,
+    ) -> Result<(), ()> {
+        match place {
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [],
+            } => {
+                self.append_local_to_string(*local, buf)?;
+            }
+            PlaceRef {
+                base:
+                    PlaceBase::Static(box Static {
+                        kind: StaticKind::Promoted(..),
+                        ..
+                    }),
+                projection: [],
+            } => {
+                buf.push_str("promoted");
+            }
+            PlaceRef {
+                base:
+                    PlaceBase::Static(box Static {
+                        kind: StaticKind::Static,
+                        def_id,
+                        ..
+                    }),
+                projection: [],
+            } => {
+                buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
+            }
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: [ProjectionElem::Deref]
+            } if self.body.local_decls[local].is_ref_for_guard() => {
+                self.append_place_to_string(
+                    PlaceRef {
+                        base: &PlaceBase::Local(local),
+                        projection: &[],
+                    },
+                    buf,
+                    autoderef,
+                    &including_downcast,
+                )?;
+            },
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: [ProjectionElem::Deref]
+            } if self.body.local_decls[local].is_ref_to_static() => {
+                let local_info = &self.body.local_decls[local].local_info;
+                if let LocalInfo::StaticRef { def_id, .. } = *local_info {
+                    buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
+                } else {
+                    unreachable!();
+                }
+            },
+            PlaceRef {
+                base,
+                projection: [proj_base @ .., elem],
+            } => {
+                match elem {
+                    ProjectionElem::Deref => {
+                        let upvar_field_projection =
+                            self.is_upvar_field_projection(place);
+                        if let Some(field) = upvar_field_projection {
+                            let var_index = field.index();
+                            let name = self.upvars[var_index].name.to_string();
+                            if self.upvars[var_index].by_ref {
+                                buf.push_str(&name);
+                            } else {
+                                buf.push_str(&format!("*{}", &name));
+                            }
+                        } else {
+                            if autoderef {
+                                // FIXME turn this recursion into iteration
+                                self.append_place_to_string(
+                                    PlaceRef {
+                                        base,
+                                        projection: proj_base,
+                                    },
+                                    buf,
+                                    autoderef,
+                                    &including_downcast,
+                                )?;
+                            } else {
+                                match (proj_base, base) {
+                                    _ => {
+                                        buf.push_str(&"*");
+                                        self.append_place_to_string(
+                                            PlaceRef {
+                                                base,
+                                                projection: proj_base,
+                                            },
+                                            buf,
+                                            autoderef,
+                                            &including_downcast,
+                                        )?;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    ProjectionElem::Downcast(..) => {
+                        self.append_place_to_string(
+                            PlaceRef {
+                                base,
+                                projection: proj_base,
+                            },
+                            buf,
+                            autoderef,
+                            &including_downcast,
+                        )?;
+                        if including_downcast.0 {
+                            return Err(());
+                        }
+                    }
+                    ProjectionElem::Field(field, _ty) => {
+                        autoderef = true;
+
+                        let upvar_field_projection =
+                            self.is_upvar_field_projection(place);
+                        if let Some(field) = upvar_field_projection {
+                            let var_index = field.index();
+                            let name = self.upvars[var_index].name.to_string();
+                            buf.push_str(&name);
+                        } else {
+                            let field_name = self.describe_field(PlaceRef {
+                                base,
+                                projection: proj_base,
+                            }, *field);
+                            self.append_place_to_string(
+                                PlaceRef {
+                                    base,
+                                    projection: proj_base,
+                                },
+                                buf,
+                                autoderef,
+                                &including_downcast,
+                            )?;
+                            buf.push_str(&format!(".{}", field_name));
+                        }
+                    }
+                    ProjectionElem::Index(index) => {
+                        autoderef = true;
+
+                        self.append_place_to_string(
+                            PlaceRef {
+                                base,
+                                projection: proj_base,
+                            },
+                            buf,
+                            autoderef,
+                            &including_downcast,
+                        )?;
+                        buf.push_str("[");
+                        if self.append_local_to_string(*index, buf).is_err() {
+                            buf.push_str("_");
+                        }
+                        buf.push_str("]");
+                    }
+                    ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
+                        autoderef = true;
+                        // Since it isn't possible to borrow an element on a particular index and
+                        // then use another while the borrow is held, don't output indices details
+                        // to avoid confusing the end-user
+                        self.append_place_to_string(
+                            PlaceRef {
+                                base,
+                                projection: proj_base,
+                            },
+                            buf,
+                            autoderef,
+                            &including_downcast,
+                        )?;
+                        buf.push_str(&"[..]");
+                    }
+                };
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
+    /// a name, or its name was generated by the compiler, then `Err` is returned
+    fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
+        let decl = &self.body.local_decls[local];
+        match self.local_names[local] {
+            Some(name) if !decl.from_compiler_desugaring() => {
+                buf.push_str(&name.as_str());
+                Ok(())
+            }
+            _ => Err(()),
+        }
+    }
+
+    /// End-user visible description of the `field`nth field of `base`
+    fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String {
+        // FIXME Place2 Make this work iteratively
+        match place {
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [],
+            } => {
+                let local = &self.body.local_decls[*local];
+                self.describe_field_from_ty(&local.ty, field, None)
+            }
+            PlaceRef {
+                base: PlaceBase::Static(static_),
+                projection: [],
+            } =>
+                self.describe_field_from_ty(&static_.ty, field, None),
+            PlaceRef {
+                base,
+                projection: [proj_base @ .., elem],
+            } => match elem {
+                ProjectionElem::Deref => {
+                    self.describe_field(PlaceRef {
+                        base,
+                        projection: proj_base,
+                    }, field)
+                }
+                ProjectionElem::Downcast(_, variant_index) => {
+                    let base_ty = Place::ty_from(
+                        place.base,
+                        place.projection,
+                        *self.body,
+                        self.infcx.tcx).ty;
+                    self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
+                }
+                ProjectionElem::Field(_, field_type) => {
+                    self.describe_field_from_ty(&field_type, field, None)
+                }
+                ProjectionElem::Index(..)
+                | ProjectionElem::ConstantIndex { .. }
+                | ProjectionElem::Subslice { .. } => {
+                    self.describe_field(PlaceRef {
+                        base,
+                        projection: proj_base,
+                    }, field)
+                }
+            },
+        }
+    }
+
+    /// End-user visible description of the `field_index`nth field of `ty`
+    fn describe_field_from_ty(
+        &self,
+        ty: Ty<'_>,
+        field: Field,
+        variant_index: Option<VariantIdx>
+    ) -> String {
+        if ty.is_box() {
+            // If the type is a box, the field is described from the boxed type
+            self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
+        } else {
+            match ty.kind {
+                ty::Adt(def, _) => {
+                    let variant = if let Some(idx) = variant_index {
+                        assert!(def.is_enum());
+                        &def.variants[idx]
+                    } else {
+                        def.non_enum_variant()
+                    };
+                    variant.fields[field.index()]
+                        .ident
+                        .to_string()
+                },
+                ty::Tuple(_) => field.index().to_string(),
+                ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                    self.describe_field_from_ty(&ty, field, variant_index)
+                }
+                ty::Array(ty, _) | ty::Slice(ty) =>
+                    self.describe_field_from_ty(&ty, field, variant_index),
+                ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
+                    // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case
+                    // the closure comes from another crate. But in that case we wouldn't
+                    // be borrowck'ing it, so we can just unwrap:
+                    let (&var_id, _) = self.infcx.tcx.upvars(def_id).unwrap()
+                        .get_index(field.index()).unwrap();
+
+                    self.infcx.tcx.hir().name(var_id).to_string()
+                }
+                _ => {
+                    // Might need a revision when the fields in trait RFC is implemented
+                    // (https://github.com/rust-lang/rfcs/pull/1546)
+                    bug!(
+                        "End-user description not implemented for field access on `{:?}`",
+                        ty
+                    );
+                }
+            }
+        }
+    }
+
+    /// Add a note that a type does not implement `Copy`
+    pub(super) fn note_type_does_not_implement_copy(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        place_desc: &str,
+        ty: Ty<'tcx>,
+        span: Option<Span>,
+    ) {
+        let message = format!(
+            "move occurs because {} has type `{}`, which does not implement the `Copy` trait",
+            place_desc,
+            ty,
+        );
+        if let Some(span) = span {
+            err.span_label(span, message);
+        } else {
+            err.note(&message);
+        }
+    }
+
+    pub(super) fn borrowed_content_source(
+        &self,
+        deref_base: PlaceRef<'cx, 'tcx>,
+    ) -> BorrowedContentSource<'tcx> {
+        let tcx = self.infcx.tcx;
+
+        // Look up the provided place and work out the move path index for it,
+        // we'll use this to check whether it was originally from an overloaded
+        // operator.
+        match self.move_data.rev_lookup.find(deref_base) {
+            LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
+                debug!("borrowed_content_source: mpi={:?}", mpi);
+
+                for i in &self.move_data.init_path_map[mpi] {
+                    let init = &self.move_data.inits[*i];
+                    debug!("borrowed_content_source: init={:?}", init);
+                    // We're only interested in statements that initialized a value, not the
+                    // initializations from arguments.
+                    let loc = match init.location {
+                        InitLocation::Statement(stmt) => stmt,
+                        _ => continue,
+                    };
+
+                    let bbd = &self.body[loc.block];
+                    let is_terminator = bbd.statements.len() == loc.statement_index;
+                    debug!(
+                        "borrowed_content_source: loc={:?} is_terminator={:?}",
+                        loc,
+                        is_terminator,
+                    );
+                    if !is_terminator {
+                        continue;
+                    } else if let Some(Terminator {
+                        kind: TerminatorKind::Call {
+                            ref func,
+                            from_hir_call: false,
+                            ..
+                        },
+                        ..
+                    }) = bbd.terminator {
+                        if let Some(source) = BorrowedContentSource::from_call(
+                            func.ty(*self.body, tcx),
+                            tcx
+                        ) {
+                            return source;
+                        }
+                    }
+                }
+            }
+            // Base is a `static` so won't be from an overloaded operator
+            _ => (),
+        };
+
+        // If we didn't find an overloaded deref or index, then assume it's a
+        // built in deref and check the type of the base.
+        let base_ty = Place::ty_from(
+            deref_base.base,
+            deref_base.projection,
+            *self.body,
+            tcx
+        ).ty;
+        if base_ty.is_unsafe_ptr() {
+            BorrowedContentSource::DerefRawPointer
+        } else if base_ty.is_mutable_ptr() {
+            BorrowedContentSource::DerefMutableRef
+        } else {
+            BorrowedContentSource::DerefSharedRef
+        }
+    }
+}
+
+impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+    /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
+    /// name where required.
+    pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
+        let mut s = String::new();
+        let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
+
+        // We need to add synthesized lifetimes where appropriate. We do
+        // this by hooking into the pretty printer and telling it to label the
+        // lifetimes without names with the value `'0`.
+        match ty.kind {
+            ty::Ref(ty::RegionKind::ReLateBound(_, br), _, _)
+            | ty::Ref(
+                ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
+                _,
+                _,
+            ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
+            _ => {}
+        }
+
+        let _ = ty.print(printer);
+        s
+    }
+
+    /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
+    /// synthesized lifetime name where required.
+    pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
+        let mut s = String::new();
+        let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
+
+        let region = match ty.kind {
+            ty::Ref(region, _, _) => {
+                match region {
+                    ty::RegionKind::ReLateBound(_, br)
+                    | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
+                        printer.region_highlight_mode.highlighting_bound_region(*br, counter)
+                    }
+                    _ => {}
+                }
+
+                region
+            }
+            _ => bug!("ty for annotation of borrow region is not a reference"),
+        };
+
+        let _ = region.print(printer);
+        s
+    }
+}
+
+// The span(s) associated to a use of a place.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub(super) enum UseSpans {
+    // The access is caused by capturing a variable for a closure.
+    ClosureUse {
+        // This is true if the captured variable was from a generator.
+        generator_kind: Option<GeneratorKind>,
+        // The span of the args of the closure, including the `move` keyword if
+        // it's present.
+        args_span: Span,
+        // The span of the first use of the captured variable inside the closure.
+        var_span: Span,
+    },
+    // This access has a single span associated to it: common case.
+    OtherUse(Span),
+}
+
+impl UseSpans {
+    pub(super) fn args_or_use(self) -> Span {
+        match self {
+            UseSpans::ClosureUse {
+                args_span: span, ..
+            }
+            | UseSpans::OtherUse(span) => span,
+        }
+    }
+
+    pub(super) fn var_or_use(self) -> Span {
+        match self {
+            UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
+        }
+    }
+
+    pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
+        match self {
+            UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
+            _ => None,
+        }
+    }
+
+    // Add a span label to the arguments of the closure, if it exists.
+    pub(super) fn args_span_label(
+        self,
+        err: &mut DiagnosticBuilder<'_>,
+        message: impl Into<String>,
+    ) {
+        if let UseSpans::ClosureUse { args_span, .. } = self {
+            err.span_label(args_span, message);
+        }
+    }
+
+    // Add a span label to the use of the captured variable, if it exists.
+    pub(super) fn var_span_label(
+        self,
+        err: &mut DiagnosticBuilder<'_>,
+        message: impl Into<String>,
+    ) {
+        if let UseSpans::ClosureUse { var_span, .. } = self {
+            err.span_label(var_span, message);
+        }
+    }
+
+    /// Returns `false` if this place is not used in a closure.
+    pub(super) fn for_closure(&self) -> bool {
+        match *self {
+            UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
+            _ => false,
+        }
+    }
+
+    /// Returns `false` if this place is not used in a generator.
+    pub(super) fn for_generator(&self) -> bool {
+        match *self {
+            UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
+            _ => false,
+        }
+    }
+
+    /// Describe the span associated with a use of a place.
+    pub(super) fn describe(&self) -> String {
+        match *self {
+            UseSpans::ClosureUse { generator_kind, .. } => if generator_kind.is_some() {
+                " in generator".to_string()
+            } else {
+                " in closure".to_string()
+            },
+            _ => "".to_string(),
+        }
+    }
+
+    pub(super) fn or_else<F>(self, if_other: F) -> Self
+    where
+        F: FnOnce() -> Self,
+    {
+        match self {
+            closure @ UseSpans::ClosureUse { .. } => closure,
+            UseSpans::OtherUse(_) => if_other(),
+        }
+    }
+}
+
+pub(super) enum BorrowedContentSource<'tcx> {
+    DerefRawPointer,
+    DerefMutableRef,
+    DerefSharedRef,
+    OverloadedDeref(Ty<'tcx>),
+    OverloadedIndex(Ty<'tcx>),
+}
+
+impl BorrowedContentSource<'tcx> {
+    pub(super) fn describe_for_unnamed_place(&self) -> String {
+        match *self {
+            BorrowedContentSource::DerefRawPointer => format!("a raw pointer"),
+            BorrowedContentSource::DerefSharedRef => format!("a shared reference"),
+            BorrowedContentSource::DerefMutableRef => {
+                format!("a mutable reference")
+            }
+            BorrowedContentSource::OverloadedDeref(ty) => {
+                if ty.is_rc() {
+                   format!("an `Rc`")
+                } else if ty.is_arc() {
+                    format!("an `Arc`")
+                } else {
+                    format!("dereference of `{}`", ty)
+                }
+            }
+            BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
+        }
+    }
+
+    pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
+        match *self {
+            BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
+            BorrowedContentSource::DerefSharedRef => Some("shared reference"),
+            BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
+            // Overloaded deref and index operators should be evaluated into a
+            // temporary. So we don't need a description here.
+            BorrowedContentSource::OverloadedDeref(_)
+            | BorrowedContentSource::OverloadedIndex(_) => None
+        }
+    }
+
+    pub(super) fn describe_for_immutable_place(&self) -> String {
+        match *self {
+            BorrowedContentSource::DerefRawPointer => format!("a `*const` pointer"),
+            BorrowedContentSource::DerefSharedRef => format!("a `&` reference"),
+            BorrowedContentSource::DerefMutableRef => {
+                 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
+            },
+            BorrowedContentSource::OverloadedDeref(ty) => {
+                if ty.is_rc() {
+                   format!("an `Rc`")
+                } else if ty.is_arc() {
+                    format!("an `Arc`")
+                } else {
+                    format!("a dereference of `{}`", ty)
+                }
+            }
+            BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
+        }
+    }
+
+    fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
+        match func.kind {
+            ty::FnDef(def_id, substs) => {
+                let trait_id = tcx.trait_of_item(def_id)?;
+
+                let lang_items = tcx.lang_items();
+                if Some(trait_id) == lang_items.deref_trait()
+                    || Some(trait_id) == lang_items.deref_mut_trait()
+                {
+                    Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
+                } else if Some(trait_id) == lang_items.index_trait()
+                    || Some(trait_id) == lang_items.index_mut_trait()
+                {
+                    Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    }
+}
+
+impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+    /// Finds the spans associated to a move or copy of move_place at location.
+    pub(super) fn move_spans(
+        &self,
+        moved_place: PlaceRef<'cx, 'tcx>, // Could also be an upvar.
+        location: Location,
+    ) -> UseSpans {
+        use self::UseSpans::*;
+
+        let stmt = match self.body[location.block].statements.get(location.statement_index) {
+            Some(stmt) => stmt,
+            None => return OtherUse(self.body.source_info(location).span),
+        };
+
+        debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
+        if let  StatementKind::Assign(
+            box(_, Rvalue::Aggregate(ref kind, ref places))
+        ) = stmt.kind {
+            let def_id = match kind {
+                box AggregateKind::Closure(def_id, _)
+                | box AggregateKind::Generator(def_id, _, _) => def_id,
+                _ => return OtherUse(stmt.source_info.span),
+            };
+
+            debug!(
+                "move_spans: def_id={:?} places={:?}",
+                def_id, places
+            );
+            if let Some((args_span, generator_kind, var_span))
+                = self.closure_span(*def_id, moved_place, places) {
+                return ClosureUse {
+                    generator_kind,
+                    args_span,
+                    var_span,
+                };
+            }
+        }
+
+        OtherUse(stmt.source_info.span)
+    }
+
+    /// Finds the span of arguments of a closure (within `maybe_closure_span`)
+    /// and its usage of the local assigned at `location`.
+    /// This is done by searching in statements succeeding `location`
+    /// and originating from `maybe_closure_span`.
+    pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
+        use self::UseSpans::*;
+        debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
+
+        let target = match self.body[location.block]
+            .statements
+            .get(location.statement_index)
+        {
+            Some(&Statement {
+                kind: StatementKind::Assign(box(ref place, _)),
+                ..
+            }) => {
+                if let Some(local) = place.as_local() {
+                    local
+                } else {
+                    return OtherUse(use_span);
+                }
+            }
+            _ => return OtherUse(use_span),
+        };
+
+        if self.body.local_kind(target) != LocalKind::Temp {
+            // operands are always temporaries.
+            return OtherUse(use_span);
+        }
+
+        for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
+            if let StatementKind::Assign(
+                box(_, Rvalue::Aggregate(ref kind, ref places))
+            ) = stmt.kind {
+                let (def_id, is_generator) = match kind {
+                    box AggregateKind::Closure(def_id, _) => (def_id, false),
+                    box AggregateKind::Generator(def_id, _, _) => (def_id, true),
+                    _ => continue,
+                };
+
+                debug!(
+                    "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
+                    def_id, is_generator, places
+                );
+                if let Some((args_span, generator_kind, var_span)) = self.closure_span(
+                    *def_id, Place::from(target).as_ref(), places
+                ) {
+                    return ClosureUse {
+                        generator_kind,
+                        args_span,
+                        var_span,
+                    };
+                } else {
+                    return OtherUse(use_span);
+                }
+            }
+
+            if use_span != stmt.source_info.span {
+                break;
+            }
+        }
+
+        OtherUse(use_span)
+    }
+
+    /// Finds the span of a captured variable within a closure or generator.
+    fn closure_span(
+        &self,
+        def_id: DefId,
+        target_place: PlaceRef<'cx, 'tcx>,
+        places: &Vec<Operand<'tcx>>,
+    ) -> Option<(Span, Option<GeneratorKind>, Span)> {
+        debug!(
+            "closure_span: def_id={:?} target_place={:?} places={:?}",
+            def_id, target_place, places
+        );
+        let hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id)?;
+        let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
+        debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
+        if let hir::ExprKind::Closure(
+            .., body_id, args_span, _
+        ) = expr {
+            for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) {
+                match place {
+                    Operand::Copy(place) |
+                    Operand::Move(place) if target_place == place.as_ref() => {
+                        debug!("closure_span: found captured local {:?}", place);
+                        let body = self.infcx.tcx.hir().body(*body_id);
+                        let generator_kind = body.generator_kind();
+                        return Some((*args_span, generator_kind, upvar.span));
+                    },
+                    _ => {}
+                }
+            }
+
+        }
+        None
+    }
+
+    /// Helper to retrieve span(s) of given borrow from the current MIR
+    /// representation
+    pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
+        let span = self.body.source_info(borrow.reserve_location).span;
+        self.borrow_spans(span, borrow.reserve_location)
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
new file mode 100644 (file)
index 0000000..938836d
--- /dev/null
@@ -0,0 +1,587 @@
+use rustc::mir::*;
+use rustc::ty;
+use rustc_errors::{DiagnosticBuilder,Applicability};
+use syntax_pos::Span;
+
+use crate::borrow_check::MirBorrowckCtxt;
+use crate::borrow_check::prefixes::PrefixSet;
+use crate::borrow_check::diagnostics::UseSpans;
+use crate::dataflow::move_paths::{
+    IllegalMoveOrigin, IllegalMoveOriginKind,
+    LookupResult, MoveError, MovePathIndex,
+};
+
+// Often when desugaring a pattern match we may have many individual moves in
+// MIR that are all part of one operation from the user's point-of-view. For
+// example:
+//
+// let (x, y) = foo()
+//
+// would move x from the 0 field of some temporary, and y from the 1 field. We
+// group such errors together for cleaner error reporting.
+//
+// Errors are kept separate if they are from places with different parent move
+// paths. For example, this generates two errors:
+//
+// let (&x, &y) = (&String::new(), &String::new());
+#[derive(Debug)]
+enum GroupedMoveError<'tcx> {
+    // Place expression can't be moved from,
+    // e.g., match x[0] { s => (), } where x: &[String]
+    MovesFromPlace {
+        original_path: Place<'tcx>,
+        span: Span,
+        move_from: Place<'tcx>,
+        kind: IllegalMoveOriginKind<'tcx>,
+        binds_to: Vec<Local>,
+    },
+    // Part of a value expression can't be moved from,
+    // e.g., match &String::new() { &x => (), }
+    MovesFromValue {
+        original_path: Place<'tcx>,
+        span: Span,
+        move_from: MovePathIndex,
+        kind: IllegalMoveOriginKind<'tcx>,
+        binds_to: Vec<Local>,
+    },
+    // Everything that isn't from pattern matching.
+    OtherIllegalMove {
+        original_path: Place<'tcx>,
+        use_spans: UseSpans,
+        kind: IllegalMoveOriginKind<'tcx>,
+    },
+}
+
+impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
+    pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
+        let grouped_errors = self.group_move_errors(move_errors);
+        for error in grouped_errors {
+            self.report(error);
+        }
+    }
+
+    fn group_move_errors(
+        &self,
+        errors: Vec<(Place<'tcx>, MoveError<'tcx>)>
+    ) -> Vec<GroupedMoveError<'tcx>> {
+        let mut grouped_errors = Vec::new();
+        for (original_path, error) in errors {
+            self.append_to_grouped_errors(&mut grouped_errors, original_path, error);
+        }
+        grouped_errors
+    }
+
+    fn append_to_grouped_errors(
+        &self,
+        grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
+        original_path: Place<'tcx>,
+        error: MoveError<'tcx>,
+    ) {
+        match error {
+            MoveError::UnionMove { .. } => {
+                unimplemented!("don't know how to report union move errors yet.")
+            }
+            MoveError::IllegalMove {
+                cannot_move_out_of: IllegalMoveOrigin { location, kind },
+            } => {
+                // Note: that the only time we assign a place isn't a temporary
+                // to a user variable is when initializing it.
+                // If that ever stops being the case, then the ever initialized
+                // flow could be used.
+                if let Some(StatementKind::Assign(
+                    box(place, Rvalue::Use(Operand::Move(move_from)))
+                )) = self.body.basic_blocks()[location.block]
+                    .statements
+                    .get(location.statement_index)
+                    .map(|stmt| &stmt.kind)
+                {
+                    if let Some(local) = place.as_local() {
+                        let local_decl = &self.body.local_decls[local];
+                        // opt_match_place is the
+                        // match_span is the span of the expression being matched on
+                        // match *x.y { ... }        match_place is Some(*x.y)
+                        //       ^^^^                match_span is the span of *x.y
+                        //
+                        // opt_match_place is None for let [mut] x = ... statements,
+                        // whether or not the right-hand side is a place expression
+                        if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                            VarBindingForm {
+                                opt_match_place: Some((ref opt_match_place, match_span)),
+                                binding_mode: _,
+                                opt_ty_info: _,
+                                pat_span: _,
+                            },
+                        ))) = local_decl.local_info {
+                            let stmt_source_info = self.body.source_info(location);
+                            self.append_binding_error(
+                                grouped_errors,
+                                kind,
+                                original_path,
+                                move_from,
+                                local,
+                                opt_match_place,
+                                match_span,
+                                stmt_source_info.span,
+                            );
+                            return;
+                        }
+                    }
+                }
+
+                let move_spans = self.move_spans(original_path.as_ref(), location);
+                grouped_errors.push(GroupedMoveError::OtherIllegalMove {
+                    use_spans: move_spans,
+                    original_path,
+                    kind,
+                });
+            }
+        }
+    }
+
+    fn append_binding_error(
+        &self,
+        grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
+        kind: IllegalMoveOriginKind<'tcx>,
+        original_path: Place<'tcx>,
+        move_from: &Place<'tcx>,
+        bind_to: Local,
+        match_place: &Option<Place<'tcx>>,
+        match_span: Span,
+        statement_span: Span,
+    ) {
+        debug!(
+            "append_binding_error(match_place={:?}, match_span={:?})",
+            match_place, match_span
+        );
+
+        let from_simple_let = match_place.is_none();
+        let match_place = match_place.as_ref().unwrap_or(move_from);
+
+        match self.move_data.rev_lookup.find(match_place.as_ref()) {
+            // Error with the match place
+            LookupResult::Parent(_) => {
+                for ge in &mut *grouped_errors {
+                    if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge {
+                        if match_span == *span {
+                            debug!("appending local({:?}) to list", bind_to);
+                            if !binds_to.is_empty() {
+                                binds_to.push(bind_to);
+                            }
+                            return;
+                        }
+                    }
+                }
+                debug!("found a new move error location");
+
+                // Don't need to point to x in let x = ... .
+                let (binds_to, span) = if from_simple_let {
+                    (vec![], statement_span)
+                } else {
+                    (vec![bind_to], match_span)
+                };
+                grouped_errors.push(GroupedMoveError::MovesFromPlace {
+                    span,
+                    move_from: match_place.clone(),
+                    original_path,
+                    kind,
+                    binds_to,
+                });
+            }
+            // Error with the pattern
+            LookupResult::Exact(_) => {
+                let mpi = match self.move_data.rev_lookup.find(move_from.as_ref()) {
+                    LookupResult::Parent(Some(mpi)) => mpi,
+                    // move_from should be a projection from match_place.
+                    _ => unreachable!("Probably not unreachable..."),
+                };
+                for ge in &mut *grouped_errors {
+                    if let GroupedMoveError::MovesFromValue {
+                        span,
+                        move_from: other_mpi,
+                        binds_to,
+                        ..
+                    } = ge
+                    {
+                        if match_span == *span && mpi == *other_mpi {
+                            debug!("appending local({:?}) to list", bind_to);
+                            binds_to.push(bind_to);
+                            return;
+                        }
+                    }
+                }
+                debug!("found a new move error location");
+                grouped_errors.push(GroupedMoveError::MovesFromValue {
+                    span: match_span,
+                    move_from: mpi,
+                    original_path,
+                    kind,
+                    binds_to: vec![bind_to],
+                });
+            }
+        };
+    }
+
+    fn report(&mut self, error: GroupedMoveError<'tcx>) {
+        let (mut err, err_span) = {
+            let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
+                match error {
+                    GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
+                    GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
+                        (span, original_path, kind)
+                    }
+                    GroupedMoveError::OtherIllegalMove {
+                        use_spans,
+                        ref original_path,
+                        ref kind
+                    } => {
+                        (use_spans.args_or_use(), original_path, kind)
+                    },
+                };
+            debug!("report: original_path={:?} span={:?}, kind={:?} \
+                   original_path.is_upvar_field_projection={:?}", original_path, span, kind,
+                   self.is_upvar_field_projection(original_path.as_ref()));
+            (
+                match kind {
+                    IllegalMoveOriginKind::Static => {
+                        unreachable!();
+                    }
+                    IllegalMoveOriginKind::BorrowedContent { target_place } => {
+                        self.report_cannot_move_from_borrowed_content(
+                            original_path,
+                            target_place,
+                            span,
+                        )
+                    }
+                    IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
+                        self.cannot_move_out_of_interior_of_drop(span, ty)
+                    }
+                    IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
+                        self.cannot_move_out_of_interior_noncopy(
+                            span, ty, Some(*is_index),
+                        ),
+                },
+                span,
+            )
+        };
+
+        self.add_move_hints(error, &mut err, err_span);
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    fn report_cannot_move_from_static(
+        &mut self,
+        place: &Place<'tcx>,
+        span: Span
+    ) -> DiagnosticBuilder<'a> {
+        let description = if place.projection.len() == 1 {
+            format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
+        } else {
+            let base_static = PlaceRef {
+                base: &place.base,
+                projection: &[ProjectionElem::Deref],
+            };
+
+            format!(
+                "`{:?}` as `{:?}` is a static item",
+                self.describe_place(place.as_ref()).unwrap(),
+                self.describe_place(base_static).unwrap(),
+            )
+        };
+
+        self.cannot_move_out_of(span, &description)
+    }
+
+    fn report_cannot_move_from_borrowed_content(
+        &mut self,
+        move_place: &Place<'tcx>,
+        deref_target_place: &Place<'tcx>,
+        span: Span,
+    ) -> DiagnosticBuilder<'a> {
+        // Inspect the type of the content behind the
+        // borrow to provide feedback about why this
+        // was a move rather than a copy.
+        let ty = deref_target_place.ty(*self.body, self.infcx.tcx).ty;
+        let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
+            .find_map(|p| self.is_upvar_field_projection(p));
+
+        let deref_base = match deref_target_place.projection.as_ref() {
+            &[ref proj_base @ .., ProjectionElem::Deref] => {
+                PlaceRef {
+                    base: &deref_target_place.base,
+                    projection: &proj_base,
+                }
+            }
+            _ => bug!("deref_target_place is not a deref projection"),
+        };
+
+        if let PlaceRef {
+            base: PlaceBase::Local(local),
+            projection: [],
+        } = deref_base {
+            let decl = &self.body.local_decls[*local];
+            if decl.is_ref_for_guard() {
+                let mut err = self.cannot_move_out_of(
+                    span,
+                    &format!("`{}` in pattern guard", self.local_names[*local].unwrap()),
+                );
+                err.note(
+                    "variables bound in patterns cannot be moved from \
+                     until after the end of the pattern guard");
+                return err;
+            } else if decl.is_ref_to_static() {
+                return self.report_cannot_move_from_static(move_place, span);
+            }
+        }
+
+        debug!("report: ty={:?}", ty);
+        let mut err = match ty.kind {
+            ty::Array(..) | ty::Slice(..) =>
+                self.cannot_move_out_of_interior_noncopy(span, ty, None),
+            ty::Closure(def_id, closure_substs)
+                if def_id == self.mir_def_id && upvar_field.is_some()
+            => {
+                let closure_kind_ty = closure_substs
+                    .as_closure().kind_ty(def_id, self.infcx.tcx);
+                let closure_kind = closure_kind_ty.to_opt_closure_kind();
+                let capture_description = match closure_kind {
+                    Some(ty::ClosureKind::Fn) => {
+                        "captured variable in an `Fn` closure"
+                    }
+                    Some(ty::ClosureKind::FnMut) => {
+                        "captured variable in an `FnMut` closure"
+                    }
+                    Some(ty::ClosureKind::FnOnce) => {
+                        bug!("closure kind does not match first argument type")
+                    }
+                    None => bug!("closure kind not inferred by borrowck"),
+                };
+
+                let upvar = &self.upvars[upvar_field.unwrap().index()];
+                let upvar_hir_id = upvar.var_hir_id;
+                let upvar_name = upvar.name;
+                let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
+
+                let place_name = self.describe_place(move_place.as_ref()).unwrap();
+
+                let place_description = if self
+                    .is_upvar_field_projection(move_place.as_ref())
+                    .is_some()
+                {
+                    format!("`{}`, a {}", place_name, capture_description)
+                } else {
+                    format!(
+                        "`{}`, as `{}` is a {}",
+                        place_name,
+                        upvar_name,
+                        capture_description,
+                    )
+                };
+
+                debug!(
+                    "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",
+                    closure_kind_ty, closure_kind, place_description,
+                );
+
+                let mut diag = self.cannot_move_out_of(span, &place_description);
+
+                diag.span_label(upvar_span, "captured outer variable");
+
+                diag
+            }
+            _ => {
+                let source = self.borrowed_content_source(deref_base);
+                match (
+                    self.describe_place(move_place.as_ref()),
+                    source.describe_for_named_place(),
+                ) {
+                    (Some(place_desc), Some(source_desc)) => {
+                        self.cannot_move_out_of(
+                            span,
+                            &format!("`{}` which is behind a {}", place_desc, source_desc),
+                        )
+                    }
+                    (_, _) => {
+                        self.cannot_move_out_of(
+                            span,
+                            &source.describe_for_unnamed_place(),
+                        )
+                    }
+                }
+            },
+        };
+        let move_ty = format!(
+            "{:?}",
+            move_place.ty(*self.body, self.infcx.tcx).ty,
+        );
+        if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
+            let is_option = move_ty.starts_with("std::option::Option");
+            let is_result = move_ty.starts_with("std::result::Result");
+            if is_option || is_result {
+                err.span_suggestion(
+                    span,
+                    &format!("consider borrowing the `{}`'s content", if is_option {
+                        "Option"
+                    } else {
+                        "Result"
+                    }),
+                    format!("{}.as_ref()", snippet),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+        err
+    }
+
+    fn add_move_hints(
+        &self,
+        error: GroupedMoveError<'tcx>,
+        err: &mut DiagnosticBuilder<'a>,
+        span: Span,
+    ) {
+        match error {
+            GroupedMoveError::MovesFromPlace {
+                mut binds_to,
+                move_from,
+                ..
+            } => {
+                if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
+                    err.span_suggestion(
+                        span,
+                        "consider borrowing here",
+                        format!("&{}", snippet),
+                        Applicability::Unspecified,
+                    );
+                }
+
+                if binds_to.is_empty() {
+                    let place_ty = move_from.ty(*self.body, self.infcx.tcx).ty;
+                    let place_desc = match self.describe_place(move_from.as_ref()) {
+                        Some(desc) => format!("`{}`", desc),
+                        None => format!("value"),
+                    };
+
+                    self.note_type_does_not_implement_copy(
+                        err,
+                        &place_desc,
+                        place_ty,
+                        Some(span)
+                    );
+                } else {
+                    binds_to.sort();
+                    binds_to.dedup();
+
+                    self.add_move_error_details(err, &binds_to);
+                }
+            }
+            GroupedMoveError::MovesFromValue { mut binds_to, .. } => {
+                binds_to.sort();
+                binds_to.dedup();
+                self.add_move_error_suggestions(err, &binds_to);
+                self.add_move_error_details(err, &binds_to);
+            }
+            // No binding. Nothing to suggest.
+            GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
+                let span = use_spans.var_or_use();
+                let place_ty = original_path.ty(*self.body, self.infcx.tcx).ty;
+                let place_desc = match self.describe_place(original_path.as_ref()) {
+                    Some(desc) => format!("`{}`", desc),
+                    None => format!("value"),
+                };
+                self.note_type_does_not_implement_copy(
+                    err,
+                    &place_desc,
+                    place_ty,
+                    Some(span),
+                );
+
+                use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
+                use_spans.var_span_label(
+                    err,
+                    format!("move occurs due to use{}", use_spans.describe()),
+                );
+            },
+        }
+    }
+
+    fn add_move_error_suggestions(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        binds_to: &[Local],
+    ) {
+        let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
+        for local in binds_to {
+            let bind_to = &self.body.local_decls[*local];
+            if let LocalInfo::User(
+                ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                    pat_span,
+                    ..
+                }))
+            ) = bind_to.local_info {
+                if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
+                {
+                    if pat_snippet.starts_with('&') {
+                        let pat_snippet = pat_snippet[1..].trim_start();
+                        let suggestion;
+                        let to_remove;
+                        if pat_snippet.starts_with("mut")
+                            && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
+                        {
+                            suggestion = pat_snippet["mut".len()..].trim_start();
+                            to_remove = "&mut";
+                        } else {
+                            suggestion = pat_snippet;
+                            to_remove = "&";
+                        }
+                        suggestions.push((
+                            pat_span,
+                            to_remove,
+                            suggestion.to_owned(),
+                        ));
+                    }
+                }
+            }
+        }
+        suggestions.sort_unstable_by_key(|&(span, _, _)| span);
+        suggestions.dedup_by_key(|&mut (span, _, _)| span);
+        for (span, to_remove, suggestion) in suggestions {
+            err.span_suggestion(
+                span,
+                &format!("consider removing the `{}`", to_remove),
+                suggestion,
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    fn add_move_error_details(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        binds_to: &[Local],
+    ) {
+        for (j, local) in binds_to.into_iter().enumerate() {
+            let bind_to = &self.body.local_decls[*local];
+            let binding_span = bind_to.source_info.span;
+
+            if j == 0 {
+                err.span_label(binding_span, "data moved here");
+            } else {
+                err.span_label(binding_span, "...and here");
+            }
+
+            if binds_to.len() == 1 {
+                self.note_type_does_not_implement_copy(
+                    err,
+                    &format!("`{}`", self.local_names[*local].unwrap()),
+                    bind_to.ty,
+                    Some(binding_span)
+                );
+            }
+        }
+
+        if binds_to.len() > 1 {
+            err.note("move occurs because these variables have types that \
+                      don't implement the `Copy` trait",
+            );
+        }
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
new file mode 100644 (file)
index 0000000..6449ae3
--- /dev/null
@@ -0,0 +1,656 @@
+use rustc::hir;
+use rustc::hir::Node;
+use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyCache};
+use rustc::mir::{Mutability, Place, PlaceRef, PlaceBase, ProjectionElem};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc_index::vec::Idx;
+use syntax_pos::Span;
+use syntax_pos::symbol::kw;
+
+use crate::borrow_check::MirBorrowckCtxt;
+use crate::borrow_check::diagnostics::BorrowedContentSource;
+use crate::util::collect_writes::FindAssignments;
+use rustc_errors::Applicability;
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub(crate) enum AccessKind {
+    MutableBorrow,
+    Mutate,
+}
+
+impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
+    pub(crate) fn report_mutability_error(
+        &mut self,
+        access_place: &Place<'tcx>,
+        span: Span,
+        the_place_err: PlaceRef<'cx, 'tcx>,
+        error_access: AccessKind,
+        location: Location,
+    ) {
+        debug!(
+            "report_mutability_error(\
+                access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\
+            )",
+            access_place, span, the_place_err, error_access, location,
+        );
+
+        let mut err;
+        let item_msg;
+        let reason;
+        let mut opt_source = None;
+        let access_place_desc = self.describe_place(access_place.as_ref());
+        debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
+
+        match the_place_err {
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [],
+            } => {
+                item_msg = format!("`{}`", access_place_desc.unwrap());
+                if access_place.as_local().is_some() {
+                    reason = ", as it is not declared as mutable".to_string();
+                } else {
+                    let name = self.local_names[*local]
+                        .expect("immutable unnamed local");
+                    reason = format!(", as `{}` is not declared as mutable", name);
+                }
+            }
+
+            PlaceRef {
+                base: _,
+                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
+            } => {
+                debug_assert!(is_closure_or_generator(
+                    Place::ty_from(
+                        &the_place_err.base,
+                        proj_base,
+                        *self.body,
+                        self.infcx.tcx
+                    ).ty));
+
+                item_msg = format!("`{}`", access_place_desc.unwrap());
+                if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
+                    reason = ", as it is not declared as mutable".to_string();
+                } else {
+                    let name = self.upvars[upvar_index.index()].name;
+                    reason = format!(", as `{}` is not declared as mutable", name);
+                }
+            }
+
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: [ProjectionElem::Deref],
+            } if self.body.local_decls[local].is_ref_for_guard() => {
+                item_msg = format!("`{}`", access_place_desc.unwrap());
+                reason = ", as it is immutable for the pattern guard".to_string();
+            }
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: [ProjectionElem::Deref],
+            } if self.body.local_decls[local].is_ref_to_static() => {
+                if access_place.projection.len() == 1 {
+                    item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
+                    reason = String::new();
+                } else {
+                    item_msg = format!("`{}`", access_place_desc.unwrap());
+                    let local_info = &self.body.local_decls[local].local_info;
+                    if let LocalInfo::StaticRef { def_id, .. } = *local_info {
+                        let static_name = &self.infcx.tcx.item_name(def_id);
+                        reason = format!(", as `{}` is an immutable static item", static_name);
+                    } else {
+                        bug!("is_ref_to_static return true, but not ref to static?");
+                    }
+                }
+            }
+            PlaceRef {
+                base: _,
+                projection: [proj_base @ .., ProjectionElem::Deref],
+            } => {
+                if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
+                    proj_base.is_empty() &&
+                    !self.upvars.is_empty() {
+                    item_msg = format!("`{}`", access_place_desc.unwrap());
+                    debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
+                    debug_assert!(is_closure_or_generator(
+                        Place::ty_from(
+                            the_place_err.base,
+                            the_place_err.projection,
+                            *self.body,
+                            self.infcx.tcx
+                        )
+                        .ty
+                    ));
+
+                    reason =
+                        if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
+                            ", as it is a captured variable in a `Fn` closure".to_string()
+                        } else {
+                            ", as `Fn` closures cannot mutate their captured variables".to_string()
+                        }
+                } else {
+                    let source = self.borrowed_content_source(PlaceRef {
+                        base: the_place_err.base,
+                        projection: proj_base,
+                    });
+                    let pointer_type = source.describe_for_immutable_place();
+                    opt_source = Some(source);
+                    if let Some(desc) = access_place_desc {
+                        item_msg = format!("`{}`", desc);
+                        reason = match error_access {
+                            AccessKind::Mutate => format!(" which is behind {}", pointer_type),
+                            AccessKind::MutableBorrow => {
+                                format!(", as it is behind {}", pointer_type)
+                            }
+                        }
+                    } else {
+                        item_msg = format!("data in {}", pointer_type);
+                        reason = String::new();
+                    }
+                }
+            }
+
+            PlaceRef {
+                base: PlaceBase::Static(_),
+                ..
+            }
+            | PlaceRef {
+                base: _,
+                projection: [.., ProjectionElem::Index(_)],
+            }
+            | PlaceRef {
+                base: _,
+                projection: [.., ProjectionElem::ConstantIndex { .. }],
+            }
+            | PlaceRef {
+                base: _,
+                projection: [.., ProjectionElem::Subslice { .. }],
+            }
+            | PlaceRef {
+                base: _,
+                projection: [.., ProjectionElem::Downcast(..)],
+            } => bug!("Unexpected immutable place."),
+        }
+
+        debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason);
+
+        // `act` and `acted_on` are strings that let us abstract over
+        // the verbs used in some diagnostic messages.
+        let act;
+        let acted_on;
+
+        let span = match error_access {
+            AccessKind::Mutate => {
+                err = self.cannot_assign(span, &(item_msg + &reason));
+                act = "assign";
+                acted_on = "written";
+                span
+            }
+            AccessKind::MutableBorrow => {
+                act = "borrow as mutable";
+                acted_on = "borrowed as mutable";
+
+                let borrow_spans = self.borrow_spans(span, location);
+                let borrow_span = borrow_spans.args_or_use();
+                err = self.cannot_borrow_path_as_mutable_because(
+                    borrow_span,
+                    &item_msg,
+                    &reason,
+                );
+                borrow_spans.var_span_label(
+                    &mut err,
+                    format!(
+                        "mutable borrow occurs due to use of `{}` in closure",
+                        // always Some() if the message is printed.
+                        self.describe_place(access_place.as_ref()).unwrap_or_default(),
+                    )
+                );
+                borrow_span
+            }
+        };
+
+        debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
+
+        match the_place_err {
+            // Suggest making an existing shared borrow in a struct definition a mutable borrow.
+            //
+            // This is applicable when we have a deref of a field access to a deref of a local -
+            // something like `*((*_1).0`. The local that we get will be a reference to the
+            // struct we've got a field access of (it must be a reference since there's a deref
+            // after the field access).
+            PlaceRef {
+                base,
+                projection: [proj_base @ ..,
+                             ProjectionElem::Deref,
+                             ProjectionElem::Field(field, _),
+                             ProjectionElem::Deref,
+                ],
+            } => {
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+
+                if let Some((span, message)) = annotate_struct_field(
+                    self.infcx.tcx,
+                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty,
+                    field,
+                ) {
+                    err.span_suggestion(
+                        span,
+                        "consider changing this to be mutable",
+                        message,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            },
+
+            // Suggest removing a `&mut` from the use of a mutable reference.
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [],
+            } if {
+                self.body.local_decls.get(*local).map(|local_decl| {
+                    if let LocalInfo::User(ClearCrossCrate::Set(
+                        mir::BindingForm::ImplicitSelf(kind)
+                    )) = local_decl.local_info {
+                        // Check if the user variable is a `&mut self` and we can therefore
+                        // suggest removing the `&mut`.
+                        //
+                        // Deliberately fall into this case for all implicit self types,
+                        // so that we don't fall in to the next case with them.
+                        kind == mir::ImplicitSelfKind::MutRef
+                    } else if Some(kw::SelfLower) == self.local_names[*local] {
+                        // Otherwise, check if the name is the self kewyord - in which case
+                        // we have an explicit self. Do the same thing in this case and check
+                        // for a `self: &mut Self` to suggest removing the `&mut`.
+                        if let ty::Ref(
+                            _, _, hir::Mutability::Mutable
+                        ) = local_decl.ty.kind {
+                            true
+                        } else {
+                            false
+                        }
+                    } else {
+                        false
+                    }
+                }).unwrap_or(false)
+            } => {
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, "try removing `&mut` here");
+            },
+
+            // We want to suggest users use `let mut` for local (user
+            // variable) mutations...
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [],
+            } if self.body.local_decls[*local].can_be_made_mutable() => {
+                // ... but it doesn't make sense to suggest it on
+                // variables that are `ref x`, `ref mut x`, `&self`,
+                // or `&mut self` (such variables are simply not
+                // mutable).
+                let local_decl = &self.body.local_decls[*local];
+                assert_eq!(local_decl.mutability, Mutability::Not);
+
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_suggestion(
+                    local_decl.source_info.span,
+                    "consider changing this to be mutable",
+                    format!("mut {}", self.local_names[*local].unwrap()),
+                    Applicability::MachineApplicable,
+                );
+            }
+
+            // Also suggest adding mut for upvars
+            PlaceRef {
+                base,
+                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
+            } => {
+                debug_assert!(is_closure_or_generator(
+                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty
+                ));
+
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+
+                let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id;
+                if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
+                {
+                    if let hir::PatKind::Binding(
+                        hir::BindingAnnotation::Unannotated,
+                        _,
+                        upvar_ident,
+                        _,
+                    ) = pat.kind
+                    {
+                        err.span_suggestion(
+                            upvar_ident.span,
+                            "consider changing this to be mutable",
+                            format!("mut {}", upvar_ident.name),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                }
+            }
+
+            // complete hack to approximate old AST-borrowck
+            // diagnostic: if the span starts with a mutable borrow of
+            // a local variable, then just suggest the user remove it.
+            PlaceRef {
+                base: PlaceBase::Local(_),
+                projection: [],
+            } if {
+                    if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
+                        snippet.starts_with("&mut ")
+                    } else {
+                        false
+                    }
+                } =>
+            {
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, "try removing `&mut` here");
+            }
+
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [ProjectionElem::Deref],
+            } if self.body.local_decls[*local].is_ref_for_guard() => {
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.note(
+                    "variables bound in patterns are immutable until the end of the pattern guard",
+                );
+            }
+
+            // We want to point out when a `&` can be readily replaced
+            // with an `&mut`.
+            //
+            // FIXME: can this case be generalized to work for an
+            // arbitrary base for the projection?
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: [ProjectionElem::Deref],
+            } if self.body.local_decls[*local].is_user_variable() =>
+            {
+                let local_decl = &self.body.local_decls[*local];
+                let suggestion = match local_decl.local_info {
+                    LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_))) => {
+                        Some(suggest_ampmut_self(self.infcx.tcx, local_decl))
+                    }
+
+                    LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+                        mir::VarBindingForm {
+                            binding_mode: ty::BindingMode::BindByValue(_),
+                            opt_ty_info,
+                            ..
+                        },
+                    ))) => Some(suggest_ampmut(
+                        self.infcx.tcx,
+                        self.body,
+                        *local,
+                        local_decl,
+                        opt_ty_info,
+                    )),
+
+                    LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+                        mir::VarBindingForm {
+                            binding_mode: ty::BindingMode::BindByReference(_),
+                            ..
+                        },
+                    ))) => {
+                        let pattern_span = local_decl.source_info.span;
+                        suggest_ref_mut(self.infcx.tcx, pattern_span)
+                            .map(|replacement| (pattern_span, replacement))
+                    }
+
+                    LocalInfo::User(ClearCrossCrate::Clear) => bug!("saw cleared local state"),
+
+                    _ => unreachable!(),
+                };
+
+                let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() {
+                    ("&", "reference")
+                } else {
+                    ("*const", "pointer")
+                };
+
+                if let Some((err_help_span, suggested_code)) = suggestion {
+                    err.span_suggestion(
+                        err_help_span,
+                        &format!("consider changing this to be a mutable {}", pointer_desc),
+                        suggested_code,
+                        Applicability::MachineApplicable,
+                    );
+                }
+
+                match self.local_names[*local] {
+                    Some(name) if !local_decl.from_compiler_desugaring() => {
+                        err.span_label(
+                            span,
+                            format!(
+                                "`{NAME}` is a `{SIGIL}` {DESC}, \
+                                so the data it refers to cannot be {ACTED_ON}",
+                                NAME = name,
+                                SIGIL = pointer_sigil,
+                                DESC = pointer_desc,
+                                ACTED_ON = acted_on
+                            ),
+                        );
+                    }
+                    _ => {
+                        err.span_label(
+                            span,
+                            format!(
+                                "cannot {ACT} through `{SIGIL}` {DESC}",
+                                ACT = act,
+                                SIGIL = pointer_sigil,
+                                DESC = pointer_desc
+                            ),
+                        );
+                    }
+                }
+            }
+
+            PlaceRef {
+                base,
+                projection: [ProjectionElem::Deref],
+            // FIXME document what is this 1 magic number about
+            } if *base == PlaceBase::Local(Local::new(1)) &&
+                  !self.upvars.is_empty() =>
+            {
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_help(
+                    self.body.span,
+                    "consider changing this to accept closures that implement `FnMut`"
+                );
+            }
+
+            PlaceRef {
+                base: _,
+                projection: [.., ProjectionElem::Deref],
+            } => {
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+
+                match opt_source {
+                    Some(BorrowedContentSource::OverloadedDeref(ty)) => {
+                        err.help(
+                            &format!(
+                                "trait `DerefMut` is required to modify through a dereference, \
+                                but it is not implemented for `{}`",
+                                ty,
+                            ),
+                        );
+                    },
+                    Some(BorrowedContentSource::OverloadedIndex(ty)) => {
+                        err.help(
+                            &format!(
+                                "trait `IndexMut` is required to modify indexed content, \
+                                but it is not implemented for `{}`",
+                                ty,
+                            ),
+                        );
+                    }
+                    _ => (),
+                }
+            }
+
+            _ => {
+                err.span_label(span, format!("cannot {ACT}", ACT = act));
+            }
+        }
+
+        err.buffer(&mut self.errors_buffer);
+    }
+}
+
+fn suggest_ampmut_self<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    local_decl: &mir::LocalDecl<'tcx>,
+) -> (Span, String) {
+    let sp = local_decl.source_info.span;
+    (sp, match tcx.sess.source_map().span_to_snippet(sp) {
+        Ok(snippet) => {
+            let lt_pos = snippet.find('\'');
+            if let Some(lt_pos) = lt_pos {
+                format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
+            } else {
+                "&mut self".to_string()
+            }
+        }
+        _ => "&mut self".to_string()
+    })
+}
+
+// When we want to suggest a user change a local variable to be a `&mut`, there
+// are three potential "obvious" things to highlight:
+//
+// let ident [: Type] [= RightHandSideExpression];
+//     ^^^^^    ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
+//     (1.)     (2.)              (3.)
+//
+// We can always fallback on highlighting the first. But chances are good that
+// the user experience will be better if we highlight one of the others if possible;
+// for example, if the RHS is present and the Type is not, then the type is going to
+// be inferred *from* the RHS, which means we should highlight that (and suggest
+// that they borrow the RHS mutably).
+//
+// This implementation attempts to emulate AST-borrowck prioritization
+// by trying (3.), then (2.) and finally falling back on (1.).
+fn suggest_ampmut<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: ReadOnlyBodyCache<'_, 'tcx>,
+    local: Local,
+    local_decl: &mir::LocalDecl<'tcx>,
+    opt_ty_info: Option<Span>,
+) -> (Span, String) {
+    let locations = body.find_assignments(local);
+    if !locations.is_empty() {
+        let assignment_rhs_span = body.source_info(locations[0]).span;
+        if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
+            if let (true, Some(ws_pos)) = (
+                src.starts_with("&'"),
+                src.find(|c: char| -> bool { c.is_whitespace() }),
+            ) {
+                let lt_name = &src[1..ws_pos];
+                let ty = &src[ws_pos..];
+                return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+            } else if src.starts_with('&') {
+                let borrowed_expr = &src[1..];
+                return (assignment_rhs_span, format!("&mut {}", borrowed_expr));
+            }
+        }
+    }
+
+    let highlight_span = match opt_ty_info {
+        // if this is a variable binding with an explicit type,
+        // try to highlight that for the suggestion.
+        Some(ty_span) => ty_span,
+
+        // otherwise, just highlight the span associated with
+        // the (MIR) LocalDecl.
+        None => local_decl.source_info.span,
+    };
+
+    if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) {
+        if let (true, Some(ws_pos)) = (
+            src.starts_with("&'"),
+            src.find(|c: char| -> bool { c.is_whitespace() }),
+        ) {
+            let lt_name = &src[1..ws_pos];
+            let ty = &src[ws_pos..];
+            return (highlight_span, format!("&{} mut{}", lt_name, ty));
+        }
+    }
+
+    let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
+    assert_eq!(ty_mut.mutbl, hir::Mutability::Immutable);
+    (highlight_span,
+     if local_decl.ty.is_region_ptr() {
+         format!("&mut {}", ty_mut.ty)
+     } else {
+         format!("*mut {}", ty_mut.ty)
+     })
+}
+
+fn is_closure_or_generator(ty: Ty<'_>) -> bool {
+    ty.is_closure() || ty.is_generator()
+}
+
+/// Adds a suggestion to a struct definition given a field access to a local.
+/// This function expects the local to be a reference to a struct in order to produce a suggestion.
+///
+/// ```text
+/// LL |     s: &'a String
+///    |        ---------- use `&'a mut String` here to make mutable
+/// ```
+fn annotate_struct_field(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    field: &mir::Field,
+) -> Option<(Span, String)> {
+    // Expect our local to be a reference to a struct of some kind.
+    if let ty::Ref(_, ty, _) = ty.kind {
+        if let ty::Adt(def, _) = ty.kind {
+            let field = def.all_fields().nth(field.index())?;
+            // Use the HIR types to construct the diagnostic message.
+            let hir_id = tcx.hir().as_local_hir_id(field.did)?;
+            let node = tcx.hir().find(hir_id)?;
+            // Now we're dealing with the actual struct that we're going to suggest a change to,
+            // we can expect a field that is an immutable reference to a type.
+            if let hir::Node::Field(field) = node {
+                if let hir::TyKind::Rptr(lifetime, hir::MutTy {
+                    mutbl: hir::Mutability::Immutable,
+                    ref ty
+                }) = field.ty.kind {
+                    // Get the snippets in two parts - the named lifetime (if there is one) and
+                    // type being referenced, that way we can reconstruct the snippet without loss
+                    // of detail.
+                    let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
+                    let lifetime_snippet = if !lifetime.is_elided() {
+                        format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
+                    } else {
+                        String::new()
+                    };
+
+                    return Some((
+                        field.ty.span,
+                        format!(
+                            "&{}mut {}",
+                            lifetime_snippet, &*type_snippet,
+                        ),
+                    ));
+                }
+            }
+        }
+    }
+
+    None
+}
+
+/// If possible, suggest replacing `ref` with `ref mut`.
+fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option<String> {
+    let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?;
+    if hi_src.starts_with("ref")
+        && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace)
+    {
+        let replacement = format!("ref mut{}", &hi_src["ref".len()..]);
+        Some(replacement)
+    } else {
+        None
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
new file mode 100644 (file)
index 0000000..7aecada
--- /dev/null
@@ -0,0 +1,319 @@
+//! Contains utilities for generating suggestions for borrowck errors related to unsatisified
+//! outlives constraints.
+
+use std::collections::BTreeMap;
+
+use log::debug;
+use rustc::{hir::def_id::DefId, infer::InferCtxt, ty::RegionVid};
+use rustc::mir::{Body, Local};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{Diagnostic, DiagnosticBuilder};
+use rustc_index::vec::IndexVec;
+use syntax_pos::symbol::Symbol;
+
+use smallvec::SmallVec;
+
+use crate::borrow_check::nll::region_infer::RegionInferenceContext;
+
+use super::{
+    RegionName, RegionNameSource, ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx,
+};
+
+/// The different things we could suggest.
+enum SuggestedConstraint {
+    /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ...
+    Outlives(RegionName, SmallVec<[RegionName; 2]>),
+
+    /// 'a = 'b
+    Equal(RegionName, RegionName),
+
+    /// 'a: 'static i.e. 'a = 'static and the user should just use 'static
+    Static(RegionName),
+}
+
+/// Collects information about outlives constraints that needed to be added for a given MIR node
+/// corresponding to a function definition.
+///
+/// Adds a help note suggesting adding a where clause with the needed constraints.
+pub struct OutlivesSuggestionBuilder<'a> {
+    /// The MIR DefId of the fn with the lifetime error.
+    mir_def_id: DefId,
+
+    local_names: &'a IndexVec<Local, Option<Symbol>>,
+
+    /// The list of outlives constraints that need to be added. Specifically, we map each free
+    /// region to all other regions that it must outlive. I will use the shorthand `fr:
+    /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be
+    /// implicit free regions that we inferred. These will need to be given names in the final
+    /// suggestion message.
+    constraints_to_add: BTreeMap<RegionVid, Vec<RegionVid>>,
+}
+
+impl OutlivesSuggestionBuilder<'a> {
+    /// Create a new builder for the given MIR node representing a fn definition.
+    crate fn new(
+        mir_def_id: DefId,
+        local_names: &'a IndexVec<Local, Option<Symbol>>,
+    ) -> Self {
+        OutlivesSuggestionBuilder {
+            mir_def_id,
+            local_names,
+            constraints_to_add: BTreeMap::default(),
+        }
+    }
+
+    /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives
+    /// suggestion.
+    //
+    // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound
+    // region or a named region, avoiding using regions with synthetic names altogether. This
+    // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args).
+    // We can probably be less conservative, since some inferred free regions are namable (e.g.
+    // the user can explicitly name them. To do this, we would allow some regions whose names
+    // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as
+    // naming the `'self` lifetime in methods, etc.
+    fn region_name_is_suggestable(name: &RegionName) -> bool {
+        match name.source {
+            RegionNameSource::NamedEarlyBoundRegion(..)
+            | RegionNameSource::NamedFreeRegion(..)
+            | RegionNameSource::Static => true,
+
+            // Don't give suggestions for upvars, closure return types, or other unnamable
+            // regions.
+            RegionNameSource::SynthesizedFreeEnvRegion(..)
+            | RegionNameSource::CannotMatchHirTy(..)
+            | RegionNameSource::MatchedHirTy(..)
+            | RegionNameSource::MatchedAdtAndSegment(..)
+            | RegionNameSource::AnonRegionFromUpvar(..)
+            | RegionNameSource::AnonRegionFromOutput(..)
+            | RegionNameSource::AnonRegionFromYieldTy(..)
+            | RegionNameSource::AnonRegionFromAsyncFn(..) => {
+                debug!("Region {:?} is NOT suggestable", name);
+                false
+            }
+        }
+    }
+
+    /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`.
+    fn region_vid_to_name(
+        &self,
+        errctx: &ErrorReportingCtx<'_, '_, '_>,
+        renctx: &mut RegionErrorNamingCtx,
+        region: RegionVid,
+    ) -> Option<RegionName> {
+        errctx
+            .region_infcx
+            .give_region_a_name(errctx, renctx, region)
+            .filter(Self::region_name_is_suggestable)
+    }
+
+    /// Compiles a list of all suggestions to be printed in the final big suggestion.
+    fn compile_all_suggestions<'tcx>(
+        &self,
+        body: &Body<'tcx>,
+        region_infcx: &RegionInferenceContext<'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> SmallVec<[SuggestedConstraint; 2]> {
+        let mut suggested = SmallVec::new();
+
+        // Keep track of variables that we have already suggested unifying so that we don't print
+        // out silly duplicate messages.
+        let mut unified_already = FxHashSet::default();
+
+        let errctx = ErrorReportingCtx {
+            region_infcx,
+            infcx,
+            body,
+            mir_def_id: self.mir_def_id,
+            local_names: self.local_names,
+
+            // We should not be suggesting naming upvars, so we pass in a dummy set of upvars that
+            // should never be used.
+            upvars: &[],
+        };
+
+        for (fr, outlived) in &self.constraints_to_add {
+            let fr_name = if let Some(fr_name) = self.region_vid_to_name(&errctx, renctx, *fr) {
+                fr_name
+            } else {
+                continue;
+            };
+
+            let outlived = outlived
+                .iter()
+                // if there is a `None`, we will just omit that constraint
+                .filter_map(|fr| {
+                    self.region_vid_to_name(&errctx, renctx, *fr).map(|rname| (fr, rname))
+                })
+                .collect::<Vec<_>>();
+
+            // No suggestable outlived lifetimes.
+            if outlived.is_empty() {
+                continue;
+            }
+
+            // There are three types of suggestions we can make:
+            // 1) Suggest a bound: 'a: 'b
+            // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we
+            //    should just replace 'a with 'static.
+            // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a
+
+            if outlived.iter().any(|(_, outlived_name)| {
+                if let RegionNameSource::Static = outlived_name.source {
+                    true
+                } else {
+                    false
+                }
+            }) {
+                suggested.push(SuggestedConstraint::Static(fr_name));
+            } else {
+                // We want to isolate out all lifetimes that should be unified and print out
+                // separate messages for them.
+
+                let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition(
+                    // Do we have both 'fr: 'r and 'r: 'fr?
+                    |(r, _)| {
+                        self.constraints_to_add
+                            .get(r)
+                            .map(|r_outlived| r_outlived.as_slice().contains(fr))
+                            .unwrap_or(false)
+                    },
+                );
+
+                for (r, bound) in unified.into_iter() {
+                    if !unified_already.contains(fr) {
+                        suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound));
+                        unified_already.insert(r);
+                    }
+                }
+
+                if !other.is_empty() {
+                    let other =
+                        other.iter().map(|(_, rname)| rname.clone()).collect::<SmallVec<_>>();
+                    suggested.push(SuggestedConstraint::Outlives(fr_name, other))
+                }
+            }
+        }
+
+        suggested
+    }
+
+    /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest.
+    crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) {
+        debug!("Collected {:?}: {:?}", fr, outlived_fr);
+
+        // Add to set of constraints for final help note.
+        self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr);
+    }
+
+    /// Emit an intermediate note on the given `Diagnostic` if the involved regions are
+    /// suggestable.
+    crate fn intermediate_suggestion(
+        &mut self,
+        errctx: &ErrorReportingCtx<'_, '_, '_>,
+        errci: &ErrorConstraintInfo,
+        renctx: &mut RegionErrorNamingCtx,
+        diag: &mut DiagnosticBuilder<'_>,
+    ) {
+        // Emit an intermediate note.
+        let fr_name = self.region_vid_to_name(errctx, renctx, errci.fr);
+        let outlived_fr_name = self.region_vid_to_name(errctx, renctx, errci.outlived_fr);
+
+        if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) {
+            if let RegionNameSource::Static = outlived_fr_name.source {
+                diag.help(&format!("consider replacing `{}` with `'static`", fr_name));
+            } else {
+                diag.help(&format!(
+                    "consider adding the following bound: `{}: {}`",
+                    fr_name, outlived_fr_name
+                ));
+            }
+        }
+    }
+
+    /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final
+    /// suggestion including all collected constraints.
+    crate fn add_suggestion<'tcx>(
+        &self,
+        body: &Body<'tcx>,
+        region_infcx: &RegionInferenceContext<'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
+        errors_buffer: &mut Vec<Diagnostic>,
+        renctx: &mut RegionErrorNamingCtx,
+    ) {
+        // No constraints to add? Done.
+        if self.constraints_to_add.is_empty() {
+            debug!("No constraints to suggest.");
+            return;
+        }
+
+        // If there is only one constraint to suggest, then we already suggested it in the
+        // intermediate suggestion above.
+        if self.constraints_to_add.len() == 1 {
+            debug!("Only 1 suggestion. Skipping.");
+            return;
+        }
+
+        // Get all suggestable constraints.
+        let suggested = self.compile_all_suggestions(body, region_infcx, infcx, renctx);
+
+        // If there are no suggestable constraints...
+        if suggested.is_empty() {
+            debug!("Only 1 suggestable constraint. Skipping.");
+            return;
+        }
+
+        // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
+        // list of diagnostics.
+        let mut diag = if suggested.len() == 1 {
+            infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
+                SuggestedConstraint::Outlives(a, bs) => {
+                    let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect();
+                    format!("add bound `{}: {}`", a, bs.join(" + "))
+                }
+
+                SuggestedConstraint::Equal(a, b) => {
+                    format!("`{}` and `{}` must be the same: replace one with the other", a, b)
+                }
+                SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a),
+            })
+        } else {
+            // Create a new diagnostic.
+            let mut diag = infcx
+                .tcx
+                .sess
+                .diagnostic()
+                .struct_help("the following changes may resolve your lifetime errors");
+
+            // Add suggestions.
+            for constraint in suggested {
+                match constraint {
+                    SuggestedConstraint::Outlives(a, bs) => {
+                        let bs: SmallVec<[String; 2]> =
+                            bs.iter().map(|r| format!("{}", r)).collect();
+                        diag.help(&format!("add bound `{}: {}`", a, bs.join(" + ")));
+                    }
+                    SuggestedConstraint::Equal(a, b) => {
+                        diag.help(&format!(
+                            "`{}` and `{}` must be the same: replace one with the other",
+                            a, b
+                        ));
+                    }
+                    SuggestedConstraint::Static(a) => {
+                        diag.help(&format!("replace `{}` with `'static`", a));
+                    }
+                }
+            }
+
+            diag
+        };
+
+        // We want this message to appear after other messages on the mir def.
+        let mir_span = infcx.tcx.def_span(self.mir_def_id);
+        diag.sort_span = mir_span.shrink_to_hi();
+
+        // Buffer the diagnostic
+        diag.buffer(errors_buffer);
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
new file mode 100644 (file)
index 0000000..66f0330
--- /dev/null
@@ -0,0 +1,930 @@
+use crate::borrow_check::nll::constraints::OutlivesConstraint;
+use crate::borrow_check::nll::region_infer::RegionInferenceContext;
+use crate::borrow_check::nll::type_check::Locations;
+use crate::borrow_check::nll::universal_regions::DefiningTy;
+use crate::borrow_check::nll::ConstraintDescription;
+use crate::borrow_check::Upvar;
+use crate::util::borrowck_errors;
+use rustc::hir::def_id::DefId;
+use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
+use rustc::infer::InferCtxt;
+use rustc::infer::NLLRegionVariableOrigin;
+use rustc::mir::{ConstraintCategory, Local, Location, Body};
+use rustc::ty::{self, RegionVid};
+use rustc_index::vec::IndexVec;
+use rustc_errors::DiagnosticBuilder;
+use std::collections::VecDeque;
+use syntax::errors::Applicability;
+use syntax::symbol::kw;
+use syntax_pos::Span;
+use syntax_pos::symbol::Symbol;
+
+use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource, RegionErrorNamingCtx};
+
+impl ConstraintDescription for ConstraintCategory {
+    fn description(&self) -> &'static str {
+        // Must end with a space. Allows for empty names to be provided.
+        match self {
+            ConstraintCategory::Assignment => "assignment ",
+            ConstraintCategory::Return => "returning this value ",
+            ConstraintCategory::Yield => "yielding this value ",
+            ConstraintCategory::UseAsConst => "using this value as a constant ",
+            ConstraintCategory::UseAsStatic => "using this value as a static ",
+            ConstraintCategory::Cast => "cast ",
+            ConstraintCategory::CallArgument => "argument ",
+            ConstraintCategory::TypeAnnotation => "type annotation ",
+            ConstraintCategory::ClosureBounds => "closure body ",
+            ConstraintCategory::SizedBound => "proving this value is `Sized` ",
+            ConstraintCategory::CopyBound => "copying this value ",
+            ConstraintCategory::OpaqueType => "opaque type ",
+            ConstraintCategory::Boring
+            | ConstraintCategory::BoringNoLocation
+            | ConstraintCategory::Internal => "",
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum Trace {
+    StartRegion,
+    FromOutlivesConstraint(OutlivesConstraint),
+    NotVisited,
+}
+
+/// Various pieces of state used when reporting borrow checker errors.
+pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
+    /// The region inference context used for borrow chekcing this MIR body.
+    pub(super) region_infcx: &'b RegionInferenceContext<'tcx>,
+
+    /// The inference context used for type checking.
+    pub(super) infcx: &'b InferCtxt<'a, 'tcx>,
+
+    /// The MIR def we are reporting errors on.
+    pub(super) mir_def_id: DefId,
+
+    /// The MIR body we are reporting errors on (for convenience).
+    pub(super) body: &'b Body<'tcx>,
+
+    /// User variable names for MIR locals (where applicable).
+    pub(super) local_names: &'b IndexVec<Local, Option<Symbol>>,
+
+    /// Any upvars for the MIR body we have kept track of during borrow checking.
+    pub(super) upvars: &'b [Upvar],
+}
+
+/// Information about the various region constraints involved in a borrow checker error.
+#[derive(Clone, Debug)]
+pub struct ErrorConstraintInfo {
+    // fr: outlived_fr
+    pub(super) fr: RegionVid,
+    pub(super) fr_is_local: bool,
+    pub(super) outlived_fr: RegionVid,
+    pub(super) outlived_fr_is_local: bool,
+
+    // Category and span for best blame constraint
+    pub(super) category: ConstraintCategory,
+    pub(super) span: Span,
+}
+
+impl<'tcx> RegionInferenceContext<'tcx> {
+    /// Tries to find the best constraint to blame for the fact that
+    /// `R: from_region`, where `R` is some region that meets
+    /// `target_test`. This works by following the constraint graph,
+    /// creating a constraint path that forces `R` to outlive
+    /// `from_region`, and then finding the best choices within that
+    /// path to blame.
+    fn best_blame_constraint(
+        &self,
+        body: &Body<'tcx>,
+        from_region: RegionVid,
+        from_region_origin: NLLRegionVariableOrigin,
+        target_test: impl Fn(RegionVid) -> bool,
+    ) -> (ConstraintCategory, bool, Span) {
+        debug!("best_blame_constraint(from_region={:?}, from_region_origin={:?})",
+            from_region, from_region_origin);
+
+        // Find all paths
+        let (path, target_region) =
+            self.find_constraint_paths_between_regions(from_region, target_test)
+                .unwrap();
+        debug!(
+            "best_blame_constraint: path={:#?}",
+            path.iter()
+                .map(|&c| format!(
+                    "{:?} ({:?}: {:?})",
+                    c,
+                    self.constraint_sccs.scc(c.sup),
+                    self.constraint_sccs.scc(c.sub),
+                ))
+                .collect::<Vec<_>>()
+        );
+
+        // Classify each of the constraints along the path.
+        let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path.iter()
+            .map(|constraint| {
+                if constraint.category == ConstraintCategory::ClosureBounds {
+                    self.retrieve_closure_constraint_info(body, &constraint)
+                } else {
+                    (constraint.category, false, constraint.locations.span(body))
+                }
+            })
+            .collect();
+        debug!(
+            "best_blame_constraint: categorized_path={:#?}",
+            categorized_path
+        );
+
+        // To find the best span to cite, we first try to look for the
+        // final constraint that is interesting and where the `sup` is
+        // not unified with the ultimate target region. The reason
+        // for this is that we have a chain of constraints that lead
+        // from the source to the target region, something like:
+        //
+        //    '0: '1 ('0 is the source)
+        //    '1: '2
+        //    '2: '3
+        //    '3: '4
+        //    '4: '5
+        //    '5: '6 ('6 is the target)
+        //
+        // Some of those regions are unified with `'6` (in the same
+        // SCC).  We want to screen those out. After that point, the
+        // "closest" constraint we have to the end is going to be the
+        // most likely to be the point where the value escapes -- but
+        // we still want to screen for an "interesting" point to
+        // highlight (e.g., a call site or something).
+        let target_scc = self.constraint_sccs.scc(target_region);
+        let mut range = 0..path.len();
+
+        // As noted above, when reporting an error, there is typically a chain of constraints
+        // leading from some "source" region which must outlive some "target" region.
+        // In most cases, we prefer to "blame" the constraints closer to the target --
+        // but there is one exception. When constraints arise from higher-ranked subtyping,
+        // we generally prefer to blame the source value,
+        // as the "target" in this case tends to be some type annotation that the user gave.
+        // Therefore, if we find that the region origin is some instantiation
+        // of a higher-ranked region, we start our search from the "source" point
+        // rather than the "target", and we also tweak a few other things.
+        //
+        // An example might be this bit of Rust code:
+        //
+        // ```rust
+        // let x: fn(&'static ()) = |_| {};
+        // let y: for<'a> fn(&'a ()) = x;
+        // ```
+        //
+        // In MIR, this will be converted into a combination of assignments and type ascriptions.
+        // In particular, the 'static is imposed through a type ascription:
+        //
+        // ```rust
+        // x = ...;
+        // AscribeUserType(x, fn(&'static ())
+        // y = x;
+        // ```
+        //
+        // We wind up ultimately with constraints like
+        //
+        // ```rust
+        // !a: 'temp1 // from the `y = x` statement
+        // 'temp1: 'temp2
+        // 'temp2: 'static // from the AscribeUserType
+        // ```
+        //
+        // and here we prefer to blame the source (the y = x statement).
+        let blame_source = match from_region_origin {
+            NLLRegionVariableOrigin::FreeRegion
+                | NLLRegionVariableOrigin::Existential { from_forall: false  } => {
+                    true
+            }
+            NLLRegionVariableOrigin::Placeholder(_)
+                | NLLRegionVariableOrigin::Existential { from_forall: true  } => {
+                    false
+            }
+        };
+
+        let find_region = |i: &usize| {
+            let constraint = path[*i];
+
+            let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
+
+            if blame_source {
+                match categorized_path[*i].0 {
+                    ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
+                    ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
+                    ConstraintCategory::TypeAnnotation | ConstraintCategory::Return |
+                    ConstraintCategory::Yield => true,
+                    _ => constraint_sup_scc != target_scc,
+                }
+            } else {
+                match categorized_path[*i].0 {
+                    ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
+                    ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
+                    _ => true
+                }
+            }
+        };
+
+        let best_choice = if blame_source {
+            range.rev().find(find_region)
+        } else {
+            range.find(find_region)
+        };
+
+        debug!("best_blame_constraint: best_choice={:?} blame_source={}",
+            best_choice, blame_source);
+
+        if let Some(i) = best_choice {
+            if let Some(next) = categorized_path.get(i + 1) {
+                if categorized_path[i].0 == ConstraintCategory::Return
+                    && next.0 == ConstraintCategory::OpaqueType
+                {
+                    // The return expression is being influenced by the return type being
+                    // impl Trait, point at the return type and not the return expr.
+                    return *next;
+                }
+            }
+            return categorized_path[i];
+        }
+
+        // If that search fails, that is.. unusual. Maybe everything
+        // is in the same SCC or something. In that case, find what
+        // appears to be the most interesting point to report to the
+        // user via an even more ad-hoc guess.
+        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+        debug!("`: sorted_path={:#?}", categorized_path);
+
+        *categorized_path.first().unwrap()
+    }
+
+    /// Walks the graph of constraints (where `'a: 'b` is considered
+    /// an edge `'a -> 'b`) to find all paths from `from_region` to
+    /// `to_region`. The paths are accumulated into the vector
+    /// `results`. The paths are stored as a series of
+    /// `ConstraintIndex` values -- in other words, a list of *edges*.
+    ///
+    /// Returns: a series of constraints as well as the region `R`
+    /// that passed the target test.
+    fn find_constraint_paths_between_regions(
+        &self,
+        from_region: RegionVid,
+        target_test: impl Fn(RegionVid) -> bool,
+    ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> {
+        let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
+        context[from_region] = Trace::StartRegion;
+
+        // Use a deque so that we do a breadth-first search. We will
+        // stop at the first match, which ought to be the shortest
+        // path (fewest constraints).
+        let mut deque = VecDeque::new();
+        deque.push_back(from_region);
+
+        while let Some(r) = deque.pop_front() {
+            debug!(
+                "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}",
+                from_region,
+                r,
+                self.region_value_str(r),
+            );
+
+            // Check if we reached the region we were looking for. If so,
+            // we can reconstruct the path that led to it and return it.
+            if target_test(r) {
+                let mut result = vec![];
+                let mut p = r;
+                loop {
+                    match context[p] {
+                        Trace::NotVisited => {
+                            bug!("found unvisited region {:?} on path to {:?}", p, r)
+                        }
+
+                        Trace::FromOutlivesConstraint(c) => {
+                            result.push(c);
+                            p = c.sup;
+                        }
+
+                        Trace::StartRegion => {
+                            result.reverse();
+                            return Some((result, r));
+                        }
+                    }
+                }
+            }
+
+            // Otherwise, walk over the outgoing constraints and
+            // enqueue any regions we find, keeping track of how we
+            // reached them.
+
+            // A constraint like `'r: 'x` can come from our constraint
+            // graph.
+            let fr_static = self.universal_regions.fr_static;
+            let outgoing_edges_from_graph = self.constraint_graph
+                .outgoing_edges(r, &self.constraints, fr_static);
+
+            // Always inline this closure because it can be hot.
+            let mut handle_constraint = #[inline(always)] |constraint: OutlivesConstraint| {
+                debug_assert_eq!(constraint.sup, r);
+                let sub_region = constraint.sub;
+                if let Trace::NotVisited = context[sub_region] {
+                    context[sub_region] = Trace::FromOutlivesConstraint(constraint);
+                    deque.push_back(sub_region);
+                }
+            };
+
+            // This loop can be hot.
+            for constraint in outgoing_edges_from_graph {
+                handle_constraint(constraint);
+            }
+
+            // Member constraints can also give rise to `'r: 'x` edges that
+            // were not part of the graph initially, so watch out for those.
+            // (But they are extremely rare; this loop is very cold.)
+            for constraint in self.applied_member_constraints(r) {
+                let p_c = &self.member_constraints[constraint.member_constraint_index];
+                let constraint = OutlivesConstraint {
+                    sup: r,
+                    sub: constraint.min_choice,
+                    locations: Locations::All(p_c.definition_span),
+                    category: ConstraintCategory::OpaqueType,
+                };
+                handle_constraint(constraint);
+            }
+        }
+
+        None
+    }
+
+    /// Report an error because the universal region `fr` was required to outlive
+    /// `outlived_fr` but it is not known to do so. For example:
+    ///
+    /// ```
+    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
+    /// ```
+    ///
+    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
+    pub(in crate::borrow_check) fn report_error<'a>(
+        &'a self,
+        body: &Body<'tcx>,
+        local_names: &IndexVec<Local, Option<Symbol>>,
+        upvars: &[Upvar],
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        fr_origin: NLLRegionVariableOrigin,
+        outlived_fr: RegionVid,
+        outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'a> {
+        debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
+
+        let (category, _, span) = self.best_blame_constraint(body, fr, fr_origin, |r| {
+            self.provides_universal_region(r, fr, outlived_fr)
+        });
+
+        debug!("report_error: category={:?} {:?}", category, span);
+        // Check if we can use one of the "nice region errors".
+        if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
+            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
+            let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
+            if let Some(diag) = nice.try_report_from_nll() {
+                return diag;
+            }
+        }
+
+        let (fr_is_local, outlived_fr_is_local): (bool, bool) = (
+            self.universal_regions.is_local_free_region(fr),
+            self.universal_regions.is_local_free_region(outlived_fr),
+        );
+
+        debug!(
+            "report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
+            fr_is_local, outlived_fr_is_local, category
+        );
+
+        let errctx = ErrorReportingCtx {
+            region_infcx: self,
+            infcx,
+            mir_def_id,
+            body,
+            local_names,
+            upvars,
+        };
+
+        let errci = ErrorConstraintInfo {
+            fr, outlived_fr, fr_is_local, outlived_fr_is_local, category, span
+        };
+
+        match (category, fr_is_local, outlived_fr_is_local) {
+            (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => {
+                self.report_fnmut_error(&errctx, &errci, renctx)
+            }
+            (ConstraintCategory::Assignment, true, false)
+            | (ConstraintCategory::CallArgument, true, false) => {
+                let mut db = self.report_escaping_data_error(&errctx, &errci, renctx);
+
+                outlives_suggestion.intermediate_suggestion(&errctx, &errci, renctx, &mut db);
+                outlives_suggestion.collect_constraint(fr, outlived_fr);
+
+                db
+            }
+            _ => {
+                let mut db = self.report_general_error(&errctx, &errci, renctx);
+
+                outlives_suggestion.intermediate_suggestion(&errctx, &errci, renctx, &mut db);
+                outlives_suggestion.collect_constraint(fr, outlived_fr);
+
+                db
+            }
+        }
+    }
+
+    /// We have a constraint `fr1: fr2` that is not satisfied, where
+    /// `fr2` represents some universal region. Here, `r` is some
+    /// region where we know that `fr1: r` and this function has the
+    /// job of determining whether `r` is "to blame" for the fact that
+    /// `fr1: fr2` is required.
+    ///
+    /// This is true under two conditions:
+    ///
+    /// - `r == fr2`
+    /// - `fr2` is `'static` and `r` is some placeholder in a universe
+    ///   that cannot be named by `fr1`; in that case, we will require
+    ///   that `fr1: 'static` because it is the only way to `fr1: r` to
+    ///   be satisfied. (See `add_incompatible_universe`.)
+    fn provides_universal_region(&self, r: RegionVid, fr1: RegionVid, fr2: RegionVid) -> bool {
+        debug!(
+            "provides_universal_region(r={:?}, fr1={:?}, fr2={:?})",
+            r, fr1, fr2
+        );
+        let result = {
+            r == fr2 || {
+                fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r)
+            }
+        };
+        debug!("provides_universal_region: result = {:?}", result);
+        result
+    }
+
+    /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
+    /// This function expects `fr` to be local and `outlived_fr` to not be local.
+    ///
+    /// ```text
+    /// error: captured variable cannot escape `FnMut` closure body
+    ///   --> $DIR/issue-53040.rs:15:8
+    ///    |
+    /// LL |     || &mut v;
+    ///    |     -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
+    ///    |     |
+    ///    |     inferred to be a `FnMut` closure
+    ///    |
+    ///    = note: `FnMut` closures only have access to their captured variables while they are
+    ///            executing...
+    ///    = note: ...therefore, returned references to captured variables will escape the closure
+    /// ```
+    fn report_fnmut_error(
+        &self,
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        errci: &ErrorConstraintInfo,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'_> {
+        let ErrorConstraintInfo {
+            outlived_fr, span, ..
+        } = errci;
+
+        let mut diag = errctx
+            .infcx
+            .tcx
+            .sess
+            .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
+
+        // We should check if the return type of this closure is in fact a closure - in that
+        // case, we can special case the error further.
+        let return_type_is_closure = self.universal_regions.unnormalized_output_ty.is_closure();
+        let message = if return_type_is_closure {
+            "returns a closure that contains a reference to a captured variable, which then \
+             escapes the closure body"
+        } else {
+            "returns a reference to a captured variable which escapes the closure body"
+        };
+
+        diag.span_label(*span, message);
+
+        match self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap().source {
+            RegionNameSource::NamedEarlyBoundRegion(fr_span)
+            | RegionNameSource::NamedFreeRegion(fr_span)
+            | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
+            | RegionNameSource::CannotMatchHirTy(fr_span, _)
+            | RegionNameSource::MatchedHirTy(fr_span)
+            | RegionNameSource::MatchedAdtAndSegment(fr_span)
+            | RegionNameSource::AnonRegionFromUpvar(fr_span, _)
+            | RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
+                diag.span_label(fr_span, "inferred to be a `FnMut` closure");
+            }
+            _ => {}
+        }
+
+        diag.note(
+            "`FnMut` closures only have access to their captured variables while they are \
+             executing...",
+        );
+        diag.note("...therefore, they cannot allow references to captured variables to escape");
+
+        diag
+    }
+
+    /// Reports a error specifically for when data is escaping a closure.
+    ///
+    /// ```text
+    /// error: borrowed data escapes outside of function
+    ///   --> $DIR/lifetime-bound-will-change-warning.rs:44:5
+    ///    |
+    /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
+    ///    |              - `x` is a reference that is only valid in the function body
+    /// LL |     // but ref_obj will not, so warn.
+    /// LL |     ref_obj(x)
+    ///    |     ^^^^^^^^^^ `x` escapes the function body here
+    /// ```
+    fn report_escaping_data_error(
+        &self,
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        errci: &ErrorConstraintInfo,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'_> {
+        let ErrorReportingCtx {
+            infcx, body, upvars, local_names, ..
+        } = errctx;
+
+        let ErrorConstraintInfo {
+            span, category, ..
+        } = errci;
+
+        let fr_name_and_span =
+            self.get_var_name_and_span_for_region(infcx.tcx, body, local_names, upvars, errci.fr);
+        let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
+            infcx.tcx,
+            body,
+            local_names,
+            upvars,
+            errci.outlived_fr,
+        );
+
+        let escapes_from = match self.universal_regions.defining_ty {
+            DefiningTy::Closure(..) => "closure",
+            DefiningTy::Generator(..) => "generator",
+            DefiningTy::FnDef(..) => "function",
+            DefiningTy::Const(..) => "const",
+        };
+
+        // Revert to the normal error in these cases.
+        // Assignments aren't "escapes" in function items.
+        if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
+            || (*category == ConstraintCategory::Assignment && escapes_from == "function")
+            || escapes_from == "const"
+        {
+            return self.report_general_error(
+                errctx,
+                &ErrorConstraintInfo {
+                    fr_is_local: true,
+                    outlived_fr_is_local: false,
+                    .. *errci
+                },
+                renctx,
+            );
+        }
+
+        let mut diag = borrowck_errors::borrowed_data_escapes_closure(
+            infcx.tcx,
+            *span,
+            escapes_from,
+        );
+
+        if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
+            diag.span_label(
+                outlived_fr_span,
+                format!(
+                    "`{}` is declared here, outside of the {} body",
+                    outlived_fr_name, escapes_from
+                ),
+            );
+        }
+
+        if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
+            diag.span_label(
+                fr_span,
+                format!(
+                    "`{}` is a reference that is only valid in the {} body",
+                    fr_name, escapes_from
+                ),
+            );
+
+            diag.span_label(
+                *span,
+                format!("`{}` escapes the {} body here", fr_name, escapes_from),
+            );
+        }
+
+        diag
+    }
+
+    /// Reports a region inference error for the general case with named/synthesized lifetimes to
+    /// explain what is happening.
+    ///
+    /// ```text
+    /// error: unsatisfied lifetime constraints
+    ///   --> $DIR/regions-creating-enums3.rs:17:5
+    ///    |
+    /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
+    ///    |                -- -- lifetime `'b` defined here
+    ///    |                |
+    ///    |                lifetime `'a` defined here
+    /// LL |     ast::add(x, y)
+    ///    |     ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
+    ///    |                    is returning data with lifetime `'b`
+    /// ```
+    fn report_general_error(
+        &self,
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        errci: &ErrorConstraintInfo,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'_> {
+        let ErrorReportingCtx {
+            infcx, mir_def_id, ..
+        } = errctx;
+        let ErrorConstraintInfo {
+            fr, fr_is_local, outlived_fr, outlived_fr_is_local, span, category, ..
+        } = errci;
+
+        let mut diag = infcx.tcx.sess.struct_span_err(
+            *span,
+            "lifetime may not live long enough"
+        );
+
+        let mir_def_name = if infcx.tcx.is_closure(*mir_def_id) {
+            "closure"
+        } else {
+            "function"
+        };
+
+        let fr_name = self.give_region_a_name(errctx, renctx, *fr).unwrap();
+        fr_name.highlight_region_name(&mut diag);
+        let outlived_fr_name = self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap();
+        outlived_fr_name.highlight_region_name(&mut diag);
+
+        match (category, outlived_fr_is_local, fr_is_local) {
+            (ConstraintCategory::Return, true, _) => {
+                diag.span_label(
+                    *span,
+                    format!(
+                        "{} was supposed to return data with lifetime `{}` but it is returning \
+                         data with lifetime `{}`",
+                        mir_def_name, outlived_fr_name, fr_name
+                    ),
+                );
+            }
+            _ => {
+                diag.span_label(
+                    *span,
+                    format!(
+                        "{}requires that `{}` must outlive `{}`",
+                        category.description(),
+                        fr_name,
+                        outlived_fr_name,
+                    ),
+                );
+            }
+        }
+
+        self.add_static_impl_trait_suggestion(infcx, &mut diag, *fr, fr_name, *outlived_fr);
+
+        diag
+    }
+
+    /// Adds a suggestion to errors where a `impl Trait` is returned.
+    ///
+    /// ```text
+    /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
+    ///       a constraint
+    ///    |
+    /// LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
+    ///    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    /// ```
+    fn add_static_impl_trait_suggestion(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        diag: &mut DiagnosticBuilder<'_>,
+        fr: RegionVid,
+        // We need to pass `fr_name` - computing it again will label it twice.
+        fr_name: RegionName,
+        outlived_fr: RegionVid,
+    ) {
+        if let (Some(f), Some(ty::RegionKind::ReStatic)) =
+            (self.to_error_region(fr), self.to_error_region(outlived_fr))
+        {
+            if let Some((ty::TyS {
+                kind: ty::Opaque(did, substs),
+                ..
+            }, _)) = infcx
+                .tcx
+                .is_suitable_region(f)
+                .map(|r| r.def_id)
+                .map(|id| infcx.tcx.return_type_impl_trait(id))
+                .unwrap_or(None)
+            {
+                // Check whether or not the impl trait return type is intended to capture
+                // data with the static lifetime.
+                //
+                // eg. check for `impl Trait + 'static` instead of `impl Trait`.
+                let has_static_predicate = {
+                    let predicates_of = infcx.tcx.predicates_of(*did);
+                    let bounds = predicates_of.instantiate(infcx.tcx, substs);
+
+                    let mut found = false;
+                    for predicate in bounds.predicates {
+                        if let ty::Predicate::TypeOutlives(binder) = predicate {
+                            if let ty::OutlivesPredicate(_, ty::RegionKind::ReStatic) =
+                                binder.skip_binder()
+                            {
+                                found = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    found
+                };
+
+                debug!(
+                    "add_static_impl_trait_suggestion: has_static_predicate={:?}",
+                    has_static_predicate
+                );
+                let static_str = kw::StaticLifetime;
+                // If there is a static predicate, then the only sensible suggestion is to replace
+                // fr with `'static`.
+                if has_static_predicate {
+                    diag.help(&format!(
+                        "consider replacing `{}` with `{}`",
+                        fr_name, static_str,
+                    ));
+                } else {
+                    // Otherwise, we should suggest adding a constraint on the return type.
+                    let span = infcx.tcx.def_span(*did);
+                    if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
+                        let suggestable_fr_name = if fr_name.was_named() {
+                            fr_name.to_string()
+                        } else {
+                            "'_".to_string()
+                        };
+
+                        diag.span_suggestion(
+                            span,
+                            &format!(
+                                "to allow this `impl Trait` to capture borrowed data with lifetime \
+                                 `{}`, add `{}` as a constraint",
+                                fr_name, suggestable_fr_name,
+                            ),
+                            format!("{} + {}", snippet, suggestable_fr_name),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                }
+            }
+        }
+    }
+
+    crate fn free_region_constraint_info(
+        &self,
+        body: &Body<'tcx>,
+        local_names: &IndexVec<Local, Option<Symbol>>,
+        upvars: &[Upvar],
+        mir_def_id: DefId,
+        infcx: &InferCtxt<'_, 'tcx>,
+        borrow_region: RegionVid,
+        outlived_region: RegionVid,
+    ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
+        let (category, from_closure, span) = self.best_blame_constraint(
+            body,
+            borrow_region,
+            NLLRegionVariableOrigin::FreeRegion,
+            |r| self.provides_universal_region(r, borrow_region, outlived_region)
+        );
+
+        let mut renctx = RegionErrorNamingCtx::new();
+        let errctx = ErrorReportingCtx {
+            infcx, body, local_names, upvars, mir_def_id,
+            region_infcx: self,
+        };
+        let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
+
+        (category, from_closure, span, outlived_fr_name)
+    }
+
+    // Finds some region R such that `fr1: R` and `R` is live at
+    // `elem`.
+    crate fn find_sub_region_live_at(
+        &self,
+        fr1: RegionVid,
+        elem: Location,
+    ) -> RegionVid {
+        debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem);
+        self.find_constraint_paths_between_regions(fr1, |r| {
+            // First look for some `r` such that `fr1: r` and `r` is live at `elem`
+            debug!(
+                "find_sub_region_live_at: liveness_constraints for {:?} are {:?}",
+                r,
+                self.liveness_constraints.region_value_str(r),
+            );
+            self.liveness_constraints.contains(r, elem)
+        }).or_else(|| {
+                // If we fail to find that, we may find some `r` such that
+                // `fr1: r` and `r` is a placeholder from some universe
+                // `fr1` cannot name. This would force `fr1` to be
+                // `'static`.
+                self.find_constraint_paths_between_regions(fr1, |r| {
+                    self.cannot_name_placeholder(fr1, r)
+                })
+            })
+            .or_else(|| {
+                // If we fail to find THAT, it may be that `fr1` is a
+                // placeholder that cannot "fit" into its SCC. In that
+                // case, there should be some `r` where `fr1: r`, both
+                // `fr1` and `r` are in the same SCC, and `fr1` is a
+                // placeholder that `r` cannot name. We can blame that
+                // edge.
+                self.find_constraint_paths_between_regions(fr1, |r| {
+                    self.constraint_sccs.scc(fr1) == self.constraint_sccs.scc(r)
+                        && self.cannot_name_placeholder(r, fr1)
+                })
+            })
+            .map(|(_path, r)| r)
+            .unwrap()
+    }
+
+    // Finds a good span to blame for the fact that `fr1` outlives `fr2`.
+    crate fn find_outlives_blame_span(
+        &self,
+        body: &Body<'tcx>,
+        fr1: RegionVid,
+        fr1_origin: NLLRegionVariableOrigin,
+        fr2: RegionVid,
+    ) -> (ConstraintCategory, Span) {
+        let (category, _, span) = self.best_blame_constraint(
+            body,
+            fr1,
+            fr1_origin,
+            |r| self.provides_universal_region(r, fr1, fr2),
+        );
+        (category, span)
+    }
+
+    fn retrieve_closure_constraint_info(
+        &self,
+        body: &Body<'tcx>,
+        constraint: &OutlivesConstraint,
+    ) -> (ConstraintCategory, bool, Span) {
+        let loc = match constraint.locations {
+            Locations::All(span) => return (constraint.category, false, span),
+            Locations::Single(loc) => loc,
+        };
+
+        let opt_span_category =
+            self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
+        opt_span_category
+            .map(|&(category, span)| (category, true, span))
+            .unwrap_or((constraint.category, false, body.source_info(loc).span))
+    }
+
+    /// Returns `true` if a closure is inferred to be an `FnMut` closure.
+    crate fn is_closure_fn_mut(&self, infcx: &InferCtxt<'_, 'tcx>, fr: RegionVid) -> bool {
+        if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
+            if let ty::BoundRegion::BrEnv = free_region.bound_region {
+                if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty {
+                    let closure_kind_ty = substs.as_closure().kind_ty(def_id, infcx.tcx);
+                    return Some(ty::ClosureKind::FnMut) == closure_kind_ty.to_opt_closure_kind();
+                }
+            }
+        }
+
+        false
+    }
+
+    /// If `r2` represents a placeholder region, then this returns
+    /// `true` if `r1` cannot name that placeholder in its
+    /// value; otherwise, returns `false`.
+    fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
+        debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
+
+        match self.definitions[r2].origin {
+            NLLRegionVariableOrigin::Placeholder(placeholder) => {
+                let universe1 = self.definitions[r1].universe;
+                debug!(
+                    "cannot_name_value_of: universe1={:?} placeholder={:?}",
+                    universe1, placeholder
+                );
+                universe1.cannot_name(placeholder.universe)
+            }
+
+            NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential { .. } => {
+                false
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
new file mode 100644 (file)
index 0000000..e2e7596
--- /dev/null
@@ -0,0 +1,836 @@
+use std::fmt::{self, Display};
+
+use rustc::hir;
+use rustc::hir::def::{Res, DefKind};
+use rustc::hir::def_id::DefId;
+use rustc::infer::InferCtxt;
+use rustc::mir::{Local, Body};
+use rustc::ty::subst::{SubstsRef, GenericArgKind};
+use rustc::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc::ty::print::RegionHighlightMode;
+use rustc_index::vec::IndexVec;
+use rustc_errors::DiagnosticBuilder;
+use syntax::symbol::kw;
+use rustc_data_structures::fx::FxHashMap;
+use syntax_pos::{Span, symbol::Symbol, DUMMY_SP};
+
+use crate::borrow_check::{
+    nll::region_infer::RegionInferenceContext,
+    nll::universal_regions::DefiningTy,
+    nll::ToRegionVid,
+    Upvar,
+};
+
+use super::region_errors::ErrorReportingCtx;
+
+/// A name for a particular region used in emitting diagnostics. This name could be a generated
+/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
+#[derive(Debug, Clone)]
+crate struct RegionName {
+    /// The name of the region (interned).
+    crate name: Symbol,
+    /// Where the region comes from.
+    crate source: RegionNameSource,
+}
+
+/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
+/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`.
+/// This helps to print the right kinds of diagnostics.
+#[derive(Debug, Clone)]
+crate enum RegionNameSource {
+    /// A bound (not free) region that was substituted at the def site (not an HRTB).
+    NamedEarlyBoundRegion(Span),
+    /// A free region that the user has a name (`'a`) for.
+    NamedFreeRegion(Span),
+    /// The `'static` region.
+    Static,
+    /// The free region corresponding to the environment of a closure.
+    SynthesizedFreeEnvRegion(Span, String),
+    /// The region name corresponds to a region where the type annotation is completely missing
+    /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
+    CannotMatchHirTy(Span, String),
+    /// The region name corresponds a reference that was found by traversing the type in the HIR.
+    MatchedHirTy(Span),
+    /// A region name from the generics list of a struct/enum/union.
+    MatchedAdtAndSegment(Span),
+    /// The region corresponding to a closure upvar.
+    AnonRegionFromUpvar(Span, String),
+    /// The region corresponding to the return type of a closure.
+    AnonRegionFromOutput(Span, String, String),
+    /// The region from a type yielded by a generator.
+    AnonRegionFromYieldTy(Span, String),
+    /// An anonymous region from an async fn.
+    AnonRegionFromAsyncFn(Span),
+}
+
+/// Records region names that have been assigned before so that we can use the same ones in later
+/// diagnostics.
+#[derive(Debug, Clone)]
+crate struct RegionErrorNamingCtx {
+    /// Record the region names generated for each region in the given
+    /// MIR def so that we can reuse them later in help/error messages.
+    renctx: FxHashMap<RegionVid, RegionName>,
+
+    /// The counter for generating new region names.
+    counter: usize,
+}
+
+impl RegionErrorNamingCtx {
+    crate fn new() -> Self {
+        Self {
+            counter: 1,
+            renctx: FxHashMap::default(),
+        }
+    }
+
+    /// Get the name of `region` if it has previously been named.
+    crate fn get(&self, region: &RegionVid) -> Option<&RegionName> {
+        self.renctx.get(region)
+    }
+
+    /// Give `region` the name `name`.
+    crate fn insert(&mut self, region: RegionVid, name: RegionName) {
+        self.renctx.insert(region, name);
+    }
+
+    /// Creates a synthetic region named `'N`, where `N` is the next value of the counter. Then,
+    /// increment the counter.
+    ///
+    /// The name is not memoized. A separate call to `insert` should be made later. (Currently,
+    /// this happens at the end of `give_region_a_name`).
+    crate fn synthesize_region_name(&mut self) -> Symbol {
+        let c = self.counter;
+        self.counter += 1;
+
+        Symbol::intern(&format!("'{:?}", c))
+    }
+}
+
+impl RegionName {
+    crate fn was_named(&self) -> bool {
+        match self.source {
+            RegionNameSource::NamedEarlyBoundRegion(..) |
+            RegionNameSource::NamedFreeRegion(..) |
+            RegionNameSource::Static => true,
+            RegionNameSource::SynthesizedFreeEnvRegion(..) |
+            RegionNameSource::CannotMatchHirTy(..) |
+            RegionNameSource::MatchedHirTy(..) |
+            RegionNameSource::MatchedAdtAndSegment(..) |
+            RegionNameSource::AnonRegionFromUpvar(..) |
+            RegionNameSource::AnonRegionFromOutput(..) |
+            RegionNameSource::AnonRegionFromYieldTy(..) |
+            RegionNameSource::AnonRegionFromAsyncFn(..) => false,
+        }
+    }
+
+    crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
+        match &self.source {
+            RegionNameSource::NamedFreeRegion(span)
+            | RegionNameSource::NamedEarlyBoundRegion(span) => {
+                diag.span_label(*span, format!("lifetime `{}` defined here", self));
+            }
+            RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
+                diag.span_label(
+                    *span,
+                    format!("lifetime `{}` represents this closure's body", self),
+                );
+                diag.note(&note);
+            }
+            RegionNameSource::CannotMatchHirTy(span, type_name) => {
+                diag.span_label(*span, format!("has type `{}`", type_name));
+            }
+            RegionNameSource::MatchedHirTy(span) |
+            RegionNameSource::AnonRegionFromAsyncFn(span) => {
+                diag.span_label(
+                    *span,
+                    format!("let's call the lifetime of this reference `{}`", self),
+                );
+            }
+            RegionNameSource::MatchedAdtAndSegment(span) => {
+                diag.span_label(*span, format!("let's call this `{}`", self));
+            }
+            RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
+                diag.span_label(
+                    *span,
+                    format!(
+                        "lifetime `{}` appears in the type of `{}`",
+                        self, upvar_name
+                    ),
+                );
+            }
+            RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => {
+                diag.span_label(
+                    *span,
+                    format!("return type{} is {}", mir_description, type_name),
+                );
+            },
+            RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
+                diag.span_label(
+                    *span,
+                    format!("yield type is {}", type_name),
+                );
+            }
+            RegionNameSource::Static => {},
+        }
+    }
+}
+
+impl Display for RegionName {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.name)
+    }
+}
+
+impl<'tcx> RegionInferenceContext<'tcx> {
+    /// Maps from an internal MIR region vid to something that we can
+    /// report to the user. In some cases, the region vids will map
+    /// directly to lifetimes that the user has a name for (e.g.,
+    /// `'static`). But frequently they will not, in which case we
+    /// have to find some way to identify the lifetime to the user. To
+    /// that end, this function takes a "diagnostic" so that it can
+    /// create auxiliary notes as needed.
+    ///
+    /// Example (function arguments):
+    ///
+    /// Suppose we are trying to give a name to the lifetime of the
+    /// reference `x`:
+    ///
+    /// ```
+    /// fn foo(x: &u32) { .. }
+    /// ```
+    ///
+    /// This function would create a label like this:
+    ///
+    /// ```
+    ///  | fn foo(x: &u32) { .. }
+    ///           ------- fully elaborated type of `x` is `&'1 u32`
+    /// ```
+    ///
+    /// and then return the name `'1` for us to use.
+    crate fn give_region_a_name(
+        &self,
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        renctx: &mut RegionErrorNamingCtx,
+        fr: RegionVid,
+    ) -> Option<RegionName> {
+        let ErrorReportingCtx {
+            infcx, body, mir_def_id, local_names, upvars, ..
+        } = errctx;
+
+        debug!("give_region_a_name(fr={:?}, counter={:?})", fr, renctx.counter);
+
+        assert!(self.universal_regions.is_universal_region(fr));
+
+        if let Some(value) = renctx.get(&fr) {
+            return Some(value.clone());
+        }
+
+        let value = self
+            .give_name_from_error_region(infcx.tcx, *mir_def_id, fr, renctx)
+            .or_else(|| {
+                self.give_name_if_anonymous_region_appears_in_arguments(
+                    infcx, body, local_names, *mir_def_id, fr, renctx,
+                )
+            })
+            .or_else(|| {
+                self.give_name_if_anonymous_region_appears_in_upvars(
+                    infcx.tcx, upvars, fr, renctx
+                )
+            })
+            .or_else(|| {
+                self.give_name_if_anonymous_region_appears_in_output(
+                    infcx, body, *mir_def_id, fr, renctx,
+                )
+            })
+            .or_else(|| {
+                self.give_name_if_anonymous_region_appears_in_yield_ty(
+                    infcx, body, *mir_def_id, fr, renctx,
+                )
+            });
+
+        if let Some(ref value) = value {
+            renctx.insert(fr, value.clone());
+        }
+
+        debug!("give_region_a_name: gave name {:?}", value);
+        value
+    }
+
+    /// Checks for the case where `fr` maps to something that the
+    /// *user* has a name for. In that case, we'll be able to map
+    /// `fr` to a `Region<'tcx>`, and that region will be one of
+    /// named variants.
+    fn give_name_from_error_region(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        let error_region = self.to_error_region(fr)?;
+
+        debug!("give_region_a_name: error_region = {:?}", error_region);
+        match error_region {
+            ty::ReEarlyBound(ebr) => {
+                if ebr.has_name() {
+                    let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
+                    Some(RegionName {
+                        name: ebr.name,
+                        source: RegionNameSource::NamedEarlyBoundRegion(span),
+                    })
+                } else {
+                    None
+                }
+            }
+
+            ty::ReStatic => Some(RegionName {
+                name: kw::StaticLifetime,
+                source: RegionNameSource::Static
+            }),
+
+            ty::ReFree(free_region) => match free_region.bound_region {
+                ty::BoundRegion::BrNamed(region_def_id, name) => {
+                    // Get the span to point to, even if we don't use the name.
+                    let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
+                    debug!("bound region named: {:?}, is_named: {:?}",
+                        name, free_region.bound_region.is_named());
+
+                    if free_region.bound_region.is_named() {
+                        // A named region that is actually named.
+                        Some(RegionName {
+                            name,
+                            source: RegionNameSource::NamedFreeRegion(span),
+                        })
+                    } else {
+                        // If we spuriously thought that the region is named, we should let the
+                        // system generate a true name for error messages. Currently this can
+                        // happen if we have an elided name in an async fn for example: the
+                        // compiler will generate a region named `'_`, but reporting such a name is
+                        // not actually useful, so we synthesize a name for it instead.
+                        let name = renctx.synthesize_region_name();
+                        Some(RegionName {
+                            name,
+                            source: RegionNameSource::AnonRegionFromAsyncFn(span),
+                        })
+                    }
+                }
+
+                ty::BoundRegion::BrEnv => {
+                    let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
+                    let def_ty = self.universal_regions.defining_ty;
+
+                    if let DefiningTy::Closure(def_id, substs) = def_ty {
+                        let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
+                            tcx.hir().expect_expr(mir_hir_id).kind
+                        {
+                            span
+                        } else {
+                            bug!("Closure is not defined by a closure expr");
+                        };
+                        let region_name = renctx.synthesize_region_name();
+
+                        let closure_kind_ty = substs.as_closure().kind_ty(def_id, tcx);
+                        let note = match closure_kind_ty.to_opt_closure_kind() {
+                            Some(ty::ClosureKind::Fn) => {
+                                "closure implements `Fn`, so references to captured variables \
+                                 can't escape the closure"
+                            }
+                            Some(ty::ClosureKind::FnMut) => {
+                                "closure implements `FnMut`, so references to captured variables \
+                                 can't escape the closure"
+                            }
+                            Some(ty::ClosureKind::FnOnce) => {
+                                bug!("BrEnv in a `FnOnce` closure");
+                            }
+                            None => bug!("Closure kind not inferred in borrow check"),
+                        };
+
+                        Some(RegionName {
+                            name: region_name,
+                            source: RegionNameSource::SynthesizedFreeEnvRegion(
+                                args_span,
+                                note.to_string(),
+                            ),
+                        })
+                    } else {
+                        // Can't have BrEnv in functions, constants or generators.
+                        bug!("BrEnv outside of closure.");
+                    }
+                }
+
+                ty::BoundRegion::BrAnon(_) => None,
+            },
+
+            ty::ReLateBound(..)
+            | ty::ReScope(..)
+            | ty::ReVar(..)
+            | ty::RePlaceholder(..)
+            | ty::ReEmpty
+            | ty::ReErased
+            | ty::ReClosureBound(..) => None,
+        }
+    }
+
+    /// Finds an argument that contains `fr` and label it with a fully
+    /// elaborated type, returning something like `'1`. Result looks
+    /// like:
+    ///
+    /// ```
+    ///  | fn foo(x: &u32) { .. }
+    ///           ------- fully elaborated type of `x` is `&'1 u32`
+    /// ```
+    fn give_name_if_anonymous_region_appears_in_arguments(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        body: &Body<'tcx>,
+        local_names: &IndexVec<Local, Option<Symbol>>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
+        let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
+
+        let arg_ty =
+            self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
+        if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument(
+            infcx,
+            mir_def_id,
+            fr,
+            arg_ty,
+            argument_index,
+            renctx,
+        ) {
+            return Some(region_name);
+        }
+
+        self.give_name_if_we_cannot_match_hir_ty(infcx, body, local_names, fr, arg_ty, renctx)
+    }
+
+    fn give_name_if_we_can_match_hir_ty_from_argument(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        mir_def_id: DefId,
+        needle_fr: RegionVid,
+        argument_ty: Ty<'tcx>,
+        argument_index: usize,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        let mir_hir_id = infcx.tcx.hir().as_local_hir_id(mir_def_id)?;
+        let fn_decl = infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
+        let argument_hir_ty: &hir::Ty = fn_decl.inputs.get(argument_index)?;
+        match argument_hir_ty.kind {
+            // This indicates a variable with no type annotation, like
+            // `|x|`... in that case, we can't highlight the type but
+            // must highlight the variable.
+            // NOTE(eddyb) this is handled in/by the sole caller
+            // (`give_name_if_anonymous_region_appears_in_arguments`).
+            hir::TyKind::Infer => None,
+
+            _ => self.give_name_if_we_can_match_hir_ty(
+                infcx.tcx,
+                needle_fr,
+                argument_ty,
+                argument_hir_ty,
+                renctx,
+            ),
+        }
+    }
+
+    /// Attempts to highlight the specific part of a type in an argument
+    /// that has no type annotation.
+    /// For example, we might produce an annotation like this:
+    ///
+    /// ```
+    ///  |     foo(|a, b| b)
+    ///  |          -  -
+    ///  |          |  |
+    ///  |          |  has type `&'1 u32`
+    ///  |          has type `&'2 u32`
+    /// ```
+    fn give_name_if_we_cannot_match_hir_ty(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        body: &Body<'tcx>,
+        local_names: &IndexVec<Local, Option<Symbol>>,
+        needle_fr: RegionVid,
+        argument_ty: Ty<'tcx>,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        let counter = renctx.counter;
+        let mut highlight = RegionHighlightMode::default();
+        highlight.highlighting_region_vid(needle_fr, counter);
+        let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)).0;
+
+        debug!(
+            "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
+            type_name, needle_fr
+        );
+        let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
+            // Only add a label if we can confirm that a region was labelled.
+            let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
+            let (_, span) =
+                self.get_argument_name_and_span_for_region(body, local_names, argument_index);
+
+            Some(RegionName {
+                // This counter value will already have been used, so this function will increment
+                // it so the next value will be used next and return the region name that would
+                // have been used.
+                name: renctx.synthesize_region_name(),
+                source: RegionNameSource::CannotMatchHirTy(span, type_name),
+            })
+        } else {
+            None
+        };
+
+        assigned_region_name
+    }
+
+    /// Attempts to highlight the specific part of a type annotation
+    /// that contains the anonymous reference we want to give a name
+    /// to. For example, we might produce an annotation like this:
+    ///
+    /// ```
+    ///  | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item = &T>> {
+    ///  |                - let's call the lifetime of this reference `'1`
+    /// ```
+    ///
+    /// the way this works is that we match up `argument_ty`, which is
+    /// a `Ty<'tcx>` (the internal form of the type) with
+    /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
+    /// annotation). We are descending through the types stepwise,
+    /// looking in to find the region `needle_fr` in the internal
+    /// type. Once we find that, we can use the span of the `hir::Ty`
+    /// to add the highlight.
+    ///
+    /// This is a somewhat imperfect process, so along the way we also
+    /// keep track of the **closest** type we've found. If we fail to
+    /// find the exact `&` or `'_` to highlight, then we may fall back
+    /// to highlighting that closest type instead.
+    fn give_name_if_we_can_match_hir_ty(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        needle_fr: RegionVid,
+        argument_ty: Ty<'tcx>,
+        argument_hir_ty: &hir::Ty,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> =
+            &mut vec![(argument_ty, argument_hir_ty)];
+
+        while let Some((ty, hir_ty)) = search_stack.pop() {
+            match (&ty.kind, &hir_ty.kind) {
+                // Check if the `argument_ty` is `&'X ..` where `'X`
+                // is the region we are looking for -- if so, and we have a `&T`
+                // on the RHS, then we want to highlight the `&` like so:
+                //
+                //     &
+                //     - let's call the lifetime of this reference `'1`
+                (
+                    ty::Ref(region, referent_ty, _),
+                    hir::TyKind::Rptr(_lifetime, referent_hir_ty),
+                ) => {
+                    if region.to_region_vid() == needle_fr {
+                        let region_name = renctx.synthesize_region_name();
+
+                        // Just grab the first character, the `&`.
+                        let source_map = tcx.sess.source_map();
+                        let ampersand_span = source_map.start_point(hir_ty.span);
+
+                        return Some(RegionName {
+                            name: region_name,
+                            source: RegionNameSource::MatchedHirTy(ampersand_span),
+                        });
+                    }
+
+                    // Otherwise, let's descend into the referent types.
+                    search_stack.push((referent_ty, &referent_hir_ty.ty));
+                }
+
+                // Match up something like `Foo<'1>`
+                (
+                    ty::Adt(_adt_def, substs),
+                    hir::TyKind::Path(hir::QPath::Resolved(None, path)),
+                ) => {
+                    match path.res {
+                        // Type parameters of the type alias have no reason to
+                        // be the same as those of the ADT.
+                        // FIXME: We should be able to do something similar to
+                        // match_adt_and_segment in this case.
+                        Res::Def(DefKind::TyAlias, _) => (),
+                        _ => if let Some(last_segment) = path.segments.last() {
+                            if let Some(name) = self.match_adt_and_segment(
+                                substs,
+                                needle_fr,
+                                last_segment,
+                                renctx,
+                                search_stack,
+                            ) {
+                                return Some(name);
+                            }
+                        }
+                    }
+                }
+
+                // The following cases don't have lifetimes, so we
+                // just worry about trying to match up the rustc type
+                // with the HIR types:
+                (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
+                    search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(elem_hir_tys));
+                }
+
+                (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
+                | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => {
+                    search_stack.push((elem_ty, elem_hir_ty));
+                }
+
+                (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => {
+                    search_stack.push((mut_ty.ty, &mut_hir_ty.ty));
+                }
+
+                _ => {
+                    // FIXME there are other cases that we could trace
+                }
+            }
+        }
+
+        return None;
+    }
+
+    /// We've found an enum/struct/union type with the substitutions
+    /// `substs` and -- in the HIR -- a path type with the final
+    /// segment `last_segment`. Try to find a `'_` to highlight in
+    /// the generic args (or, if not, to produce new zipped pairs of
+    /// types+hir to search through).
+    fn match_adt_and_segment<'hir>(
+        &self,
+        substs: SubstsRef<'tcx>,
+        needle_fr: RegionVid,
+        last_segment: &'hir hir::PathSegment,
+        renctx: &mut RegionErrorNamingCtx,
+        search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
+    ) -> Option<RegionName> {
+        // Did the user give explicit arguments? (e.g., `Foo<..>`)
+        let args = last_segment.args.as_ref()?;
+        let lifetime =
+            self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
+        match lifetime.name {
+            hir::LifetimeName::Param(_)
+            | hir::LifetimeName::Error
+            | hir::LifetimeName::Static
+            | hir::LifetimeName::Underscore => {
+                let region_name = renctx.synthesize_region_name();
+                let ampersand_span = lifetime.span;
+                Some(RegionName {
+                    name: region_name,
+                    source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
+                })
+            }
+
+            hir::LifetimeName::ImplicitObjectLifetimeDefault
+            | hir::LifetimeName::Implicit => {
+                // In this case, the user left off the lifetime; so
+                // they wrote something like:
+                //
+                // ```
+                // x: Foo<T>
+                // ```
+                //
+                // where the fully elaborated form is `Foo<'_, '1,
+                // T>`. We don't consider this a match; instead we let
+                // the "fully elaborated" type fallback above handle
+                // it.
+                None
+            }
+        }
+    }
+
+    /// We've found an enum/struct/union type with the substitutions
+    /// `substs` and -- in the HIR -- a path with the generic
+    /// arguments `args`. If `needle_fr` appears in the args, return
+    /// the `hir::Lifetime` that corresponds to it. If not, push onto
+    /// `search_stack` the types+hir to search through.
+    fn try_match_adt_and_generic_args<'hir>(
+        &self,
+        substs: SubstsRef<'tcx>,
+        needle_fr: RegionVid,
+        args: &'hir hir::GenericArgs,
+        search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
+    ) -> Option<&'hir hir::Lifetime> {
+        for (kind, hir_arg) in substs.iter().zip(&args.args) {
+            match (kind.unpack(), hir_arg) {
+                (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
+                    if r.to_region_vid() == needle_fr {
+                        return Some(lt);
+                    }
+                }
+
+                (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
+                    search_stack.push((ty, hir_ty));
+                }
+
+                (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
+                    // Lifetimes cannot be found in consts, so we don't need
+                    // to search anything here.
+                }
+
+                (GenericArgKind::Lifetime(_), _)
+                | (GenericArgKind::Type(_), _)
+                | (GenericArgKind::Const(_), _) => {
+                    // I *think* that HIR lowering should ensure this
+                    // doesn't happen, even in erroneous
+                    // programs. Else we should use delay-span-bug.
+                    span_bug!(
+                        hir_arg.span(),
+                        "unmatched subst and hir arg: found {:?} vs {:?}",
+                        kind,
+                        hir_arg,
+                    );
+                }
+            }
+        }
+
+        None
+    }
+
+    /// Finds a closure upvar that contains `fr` and label it with a
+    /// fully elaborated type, returning something like `'1`. Result
+    /// looks like:
+    ///
+    /// ```
+    ///  | let x = Some(&22);
+    ///        - fully elaborated type of `x` is `Option<&'1 u32>`
+    /// ```
+    fn give_name_if_anonymous_region_appears_in_upvars(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        upvars: &[Upvar],
+        fr: RegionVid,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
+        let (upvar_name, upvar_span) =
+            self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index);
+        let region_name = renctx.synthesize_region_name();
+
+        Some(RegionName {
+            name: region_name,
+            source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()),
+        })
+    }
+
+    /// Checks for arguments appearing in the (closure) return type. It
+    /// must be a closure since, in a free fn, such an argument would
+    /// have to either also appear in an argument (if using elision)
+    /// or be early bound (named, not in argument).
+    fn give_name_if_anonymous_region_appears_in_output(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        body: &Body<'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        let tcx = infcx.tcx;
+
+        let return_ty = self.universal_regions.unnormalized_output_ty;
+        debug!(
+            "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}",
+            return_ty
+        );
+        if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
+            return None;
+        }
+
+        let mut highlight = RegionHighlightMode::default();
+        highlight.highlighting_region_vid(fr, renctx.counter);
+        let type_name = infcx.extract_type_name(&return_ty, Some(highlight)).0;
+
+        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
+
+        let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) {
+            hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure(_, return_ty, _, span, gen_move),
+                ..
+            }) => (
+                match return_ty.output {
+                    hir::FunctionRetTy::DefaultReturn(_) => tcx.sess.source_map().end_point(*span),
+                    hir::FunctionRetTy::Return(_) => return_ty.output.span(),
+                },
+                if gen_move.is_some() {
+                    " of generator"
+                } else {
+                    " of closure"
+                },
+            ),
+            hir::Node::ImplItem(hir::ImplItem {
+                kind: hir::ImplItemKind::Method(method_sig, _),
+                ..
+            }) => (method_sig.decl.output.span(), ""),
+            _ => (body.span, ""),
+        };
+
+        Some(RegionName {
+            // This counter value will already have been used, so this function will increment it
+            // so the next value will be used next and return the region name that would have been
+            // used.
+            name: renctx.synthesize_region_name(),
+            source: RegionNameSource::AnonRegionFromOutput(
+                return_span,
+                mir_description.to_string(),
+                type_name,
+            ),
+        })
+    }
+
+    fn give_name_if_anonymous_region_appears_in_yield_ty(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        body: &Body<'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> Option<RegionName> {
+        // Note: generators from `async fn` yield `()`, so we don't have to
+        // worry about them here.
+        let yield_ty = self.universal_regions.yield_ty?;
+        debug!(
+            "give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}",
+            yield_ty,
+        );
+
+        let tcx = infcx.tcx;
+
+        if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
+            return None;
+        }
+
+        let mut highlight = RegionHighlightMode::default();
+        highlight.highlighting_region_vid(fr, renctx.counter);
+        let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)).0;
+
+        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
+
+        let yield_span = match tcx.hir().get(mir_hir_id) {
+            hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure(_, _, _, span, _),
+                ..
+            }) => (
+                tcx.sess.source_map().end_point(*span)
+            ),
+            _ => body.span,
+        };
+
+        debug!(
+            "give_name_if_anonymous_region_appears_in_yield_ty: \
+             type_name = {:?}, yield_span = {:?}",
+            yield_span,
+            type_name,
+        );
+
+        Some(RegionName {
+            name: renctx.synthesize_region_name(),
+            source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
+        })
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/var_name.rs b/src/librustc_mir/borrow_check/diagnostics/var_name.rs
new file mode 100644 (file)
index 0000000..1ac44c4
--- /dev/null
@@ -0,0 +1,136 @@
+use crate::borrow_check::nll::region_infer::RegionInferenceContext;
+use crate::borrow_check::nll::ToRegionVid;
+use crate::borrow_check::Upvar;
+use rustc::mir::{Local, Body};
+use rustc::ty::{RegionVid, TyCtxt};
+use rustc_index::vec::{Idx, IndexVec};
+use syntax::source_map::Span;
+use syntax_pos::symbol::Symbol;
+
+impl<'tcx> RegionInferenceContext<'tcx> {
+    crate fn get_var_name_and_span_for_region(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        body: &Body<'tcx>,
+        local_names: &IndexVec<Local, Option<Symbol>>,
+        upvars: &[Upvar],
+        fr: RegionVid,
+    ) -> Option<(Option<Symbol>, Span)> {
+        debug!("get_var_name_and_span_for_region(fr={:?})", fr);
+        assert!(self.universal_regions.is_universal_region(fr));
+
+        debug!("get_var_name_and_span_for_region: attempting upvar");
+        self.get_upvar_index_for_region(tcx, fr)
+            .map(|index| {
+                let (name, span) =
+                    self.get_upvar_name_and_span_for_region(tcx, upvars, index);
+                (Some(name), span)
+            })
+            .or_else(|| {
+                debug!("get_var_name_and_span_for_region: attempting argument");
+                self.get_argument_index_for_region(tcx, fr).map(|index| {
+                    self.get_argument_name_and_span_for_region(body, local_names, index)
+                })
+            })
+    }
+
+    /// Search the upvars (if any) to find one that references fr. Return its index.
+    crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option<usize> {
+        let upvar_index = self
+            .universal_regions
+            .defining_ty
+            .upvar_tys(tcx)
+            .position(|upvar_ty| {
+                debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
+                tcx.any_free_region_meets(&upvar_ty, |r| {
+                    let r = r.to_region_vid();
+                    debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr);
+                    r == fr
+                })
+            })?;
+
+        let upvar_ty = self
+            .universal_regions
+            .defining_ty
+            .upvar_tys(tcx)
+            .nth(upvar_index);
+
+        debug!(
+            "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
+            fr, upvar_index, upvar_ty,
+        );
+
+        Some(upvar_index)
+    }
+
+    /// Given the index of an upvar, finds its name and the span from where it was
+    /// declared.
+    crate fn get_upvar_name_and_span_for_region(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        upvars: &[Upvar],
+        upvar_index: usize,
+    ) -> (Symbol, Span) {
+        let upvar_hir_id = upvars[upvar_index].var_hir_id;
+        debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id);
+
+        let upvar_name = tcx.hir().name(upvar_hir_id);
+        let upvar_span = tcx.hir().span(upvar_hir_id);
+        debug!("get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}",
+               upvar_name, upvar_span);
+
+        (upvar_name, upvar_span)
+    }
+
+    /// Search the argument types for one that references fr (which should be a free region).
+    /// Returns Some(_) with the index of the input if one is found.
+    ///
+    /// N.B., in the case of a closure, the index is indexing into the signature as seen by the
+    /// user - in particular, index 0 is not the implicit self parameter.
+    crate fn get_argument_index_for_region(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        fr: RegionVid,
+    ) -> Option<usize> {
+        let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
+        let argument_index = self
+            .universal_regions
+            .unnormalized_input_tys
+            .iter()
+            .skip(implicit_inputs)
+            .position(|arg_ty| {
+                debug!(
+                    "get_argument_index_for_region: arg_ty = {:?}",
+                    arg_ty
+                );
+                tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
+            })?;
+
+        debug!(
+            "get_argument_index_for_region: found {:?} in argument {} which has type {:?}",
+            fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index],
+        );
+
+        Some(argument_index)
+    }
+
+    /// Given the index of an argument, finds its name (if any) and the span from where it was
+    /// declared.
+    crate fn get_argument_name_and_span_for_region(
+        &self,
+        body: &Body<'tcx>,
+        local_names: &IndexVec<Local, Option<Symbol>>,
+        argument_index: usize,
+    ) -> (Option<Symbol>, Span) {
+        let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
+        let argument_local = Local::new(implicit_inputs + argument_index + 1);
+        debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
+
+        let argument_name = local_names[argument_local];
+        let argument_span = body.local_decls[argument_local].source_info.span;
+        debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
+               argument_name, argument_span);
+
+        (argument_name, argument_span)
+    }
+}
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
deleted file mode 100644 (file)
index 9953d28..0000000
+++ /dev/null
@@ -1,916 +0,0 @@
-use rustc::hir;
-use rustc::hir::def::Namespace;
-use rustc::hir::def_id::DefId;
-use rustc::hir::GeneratorKind;
-use rustc::mir::{
-    AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand,
-    Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
-    Static, StaticKind, Terminator, TerminatorKind,
-};
-use rustc::ty::{self, DefIdTree, Ty, TyCtxt};
-use rustc::ty::layout::VariantIdx;
-use rustc::ty::print::Print;
-use rustc_errors::DiagnosticBuilder;
-use syntax_pos::Span;
-
-use super::borrow_set::BorrowData;
-use super::MirBorrowckCtxt;
-use crate::dataflow::move_paths::{InitLocation, LookupResult};
-
-pub(super) struct IncludingDowncast(pub(super) bool);
-
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
-    /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
-    /// is moved after being invoked.
-    ///
-    /// ```text
-    /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
-    ///       its environment
-    ///   --> $DIR/issue-42065.rs:16:29
-    ///    |
-    /// LL |         for (key, value) in dict {
-    ///    |                             ^^^^
-    /// ```
-    pub(super) fn add_moved_or_invoked_closure_note(
-        &self,
-        location: Location,
-        place: PlaceRef<'cx, 'tcx>,
-        diag: &mut DiagnosticBuilder<'_>,
-    ) {
-        debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
-        let mut target = place.local_or_deref_local();
-        for stmt in &self.body[location.block].statements[location.statement_index..] {
-            debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
-            if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
-                debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
-                match from {
-                    Operand::Copy(ref place) |
-                    Operand::Move(ref place) if target == place.local_or_deref_local() =>
-                        target = into.local_or_deref_local(),
-                    _ => {},
-                }
-            }
-        }
-
-        // Check if we are attempting to call a closure after it has been invoked.
-        let terminator = self.body[location.block].terminator();
-        debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
-        if let TerminatorKind::Call {
-            func: Operand::Constant(box Constant {
-                literal: ty::Const {
-                    ty: &ty::TyS { kind: ty::FnDef(id, _), ..  },
-                    ..
-                },
-                ..
-            }),
-            args,
-            ..
-        } = &terminator.kind {
-            debug!("add_moved_or_invoked_closure_note: id={:?}", id);
-            if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
-                let closure = match args.first() {
-                    Some(Operand::Copy(ref place)) |
-                    Some(Operand::Move(ref place)) if target == place.local_or_deref_local() =>
-                        place.local_or_deref_local().unwrap(),
-                    _ => return,
-                };
-
-                debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
-                if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind {
-                    let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
-
-                    if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
-                        .closure_kind_origins()
-                        .get(hir_id)
-                    {
-                        diag.span_note(
-                            *span,
-                            &format!(
-                                "closure cannot be invoked more than once because it moves the \
-                                 variable `{}` out of its environment",
-                                name,
-                            ),
-                        );
-                        return;
-                    }
-                }
-            }
-        }
-
-        // Check if we are just moving a closure after it has been invoked.
-        if let Some(target) = target {
-            if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind {
-                let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
-
-                if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
-                    .closure_kind_origins()
-                    .get(hir_id)
-                {
-                    diag.span_note(
-                        *span,
-                        &format!(
-                            "closure cannot be moved more than once as it is not `Copy` due to \
-                             moving the variable `{}` out of its environment",
-                             name
-                        ),
-                    );
-                }
-            }
-        }
-    }
-
-    /// End-user visible description of `place` if one can be found. If the
-    /// place is a temporary for instance, None will be returned.
-    pub(super) fn describe_place(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option<String> {
-        self.describe_place_with_options(place_ref, IncludingDowncast(false))
-    }
-
-    /// End-user visible description of `place` if one can be found. If the
-    /// place is a temporary for instance, None will be returned.
-    /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
-    /// `Downcast` and `IncludingDowncast` is true
-    pub(super) fn describe_place_with_options(
-        &self,
-        place: PlaceRef<'cx, 'tcx>,
-        including_downcast: IncludingDowncast,
-    ) -> Option<String> {
-        let mut buf = String::new();
-        match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
-            Ok(()) => Some(buf),
-            Err(()) => None,
-        }
-    }
-
-    /// Appends end-user visible description of `place` to `buf`.
-    fn append_place_to_string(
-        &self,
-        place: PlaceRef<'cx, 'tcx>,
-        buf: &mut String,
-        mut autoderef: bool,
-        including_downcast: &IncludingDowncast,
-    ) -> Result<(), ()> {
-        match place {
-            PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [],
-            } => {
-                self.append_local_to_string(*local, buf)?;
-            }
-            PlaceRef {
-                base:
-                    PlaceBase::Static(box Static {
-                        kind: StaticKind::Promoted(..),
-                        ..
-                    }),
-                projection: [],
-            } => {
-                buf.push_str("promoted");
-            }
-            PlaceRef {
-                base:
-                    PlaceBase::Static(box Static {
-                        kind: StaticKind::Static,
-                        def_id,
-                        ..
-                    }),
-                projection: [],
-            } => {
-                buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
-            }
-            PlaceRef {
-                base: &PlaceBase::Local(local),
-                projection: [ProjectionElem::Deref]
-            } if self.body.local_decls[local].is_ref_for_guard() => {
-                self.append_place_to_string(
-                    PlaceRef {
-                        base: &PlaceBase::Local(local),
-                        projection: &[],
-                    },
-                    buf,
-                    autoderef,
-                    &including_downcast,
-                )?;
-            },
-            PlaceRef {
-                base: &PlaceBase::Local(local),
-                projection: [ProjectionElem::Deref]
-            } if self.body.local_decls[local].is_ref_to_static() => {
-                let local_info = &self.body.local_decls[local].local_info;
-                if let LocalInfo::StaticRef { def_id, .. } = *local_info {
-                    buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
-                } else {
-                    unreachable!();
-                }
-            },
-            PlaceRef {
-                base,
-                projection: [proj_base @ .., elem],
-            } => {
-                match elem {
-                    ProjectionElem::Deref => {
-                        let upvar_field_projection =
-                            self.is_upvar_field_projection(place);
-                        if let Some(field) = upvar_field_projection {
-                            let var_index = field.index();
-                            let name = self.upvars[var_index].name.to_string();
-                            if self.upvars[var_index].by_ref {
-                                buf.push_str(&name);
-                            } else {
-                                buf.push_str(&format!("*{}", &name));
-                            }
-                        } else {
-                            if autoderef {
-                                // FIXME turn this recursion into iteration
-                                self.append_place_to_string(
-                                    PlaceRef {
-                                        base,
-                                        projection: proj_base,
-                                    },
-                                    buf,
-                                    autoderef,
-                                    &including_downcast,
-                                )?;
-                            } else {
-                                match (proj_base, base) {
-                                    _ => {
-                                        buf.push_str(&"*");
-                                        self.append_place_to_string(
-                                            PlaceRef {
-                                                base,
-                                                projection: proj_base,
-                                            },
-                                            buf,
-                                            autoderef,
-                                            &including_downcast,
-                                        )?;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    ProjectionElem::Downcast(..) => {
-                        self.append_place_to_string(
-                            PlaceRef {
-                                base,
-                                projection: proj_base,
-                            },
-                            buf,
-                            autoderef,
-                            &including_downcast,
-                        )?;
-                        if including_downcast.0 {
-                            return Err(());
-                        }
-                    }
-                    ProjectionElem::Field(field, _ty) => {
-                        autoderef = true;
-
-                        let upvar_field_projection =
-                            self.is_upvar_field_projection(place);
-                        if let Some(field) = upvar_field_projection {
-                            let var_index = field.index();
-                            let name = self.upvars[var_index].name.to_string();
-                            buf.push_str(&name);
-                        } else {
-                            let field_name = self.describe_field(PlaceRef {
-                                base,
-                                projection: proj_base,
-                            }, *field);
-                            self.append_place_to_string(
-                                PlaceRef {
-                                    base,
-                                    projection: proj_base,
-                                },
-                                buf,
-                                autoderef,
-                                &including_downcast,
-                            )?;
-                            buf.push_str(&format!(".{}", field_name));
-                        }
-                    }
-                    ProjectionElem::Index(index) => {
-                        autoderef = true;
-
-                        self.append_place_to_string(
-                            PlaceRef {
-                                base,
-                                projection: proj_base,
-                            },
-                            buf,
-                            autoderef,
-                            &including_downcast,
-                        )?;
-                        buf.push_str("[");
-                        if self.append_local_to_string(*index, buf).is_err() {
-                            buf.push_str("_");
-                        }
-                        buf.push_str("]");
-                    }
-                    ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
-                        autoderef = true;
-                        // Since it isn't possible to borrow an element on a particular index and
-                        // then use another while the borrow is held, don't output indices details
-                        // to avoid confusing the end-user
-                        self.append_place_to_string(
-                            PlaceRef {
-                                base,
-                                projection: proj_base,
-                            },
-                            buf,
-                            autoderef,
-                            &including_downcast,
-                        )?;
-                        buf.push_str(&"[..]");
-                    }
-                };
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
-    /// a name, or its name was generated by the compiler, then `Err` is returned
-    fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
-        let decl = &self.body.local_decls[local];
-        match self.local_names[local] {
-            Some(name) if !decl.from_compiler_desugaring() => {
-                buf.push_str(&name.as_str());
-                Ok(())
-            }
-            _ => Err(()),
-        }
-    }
-
-    /// End-user visible description of the `field`nth field of `base`
-    fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String {
-        // FIXME Place2 Make this work iteratively
-        match place {
-            PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [],
-            } => {
-                let local = &self.body.local_decls[*local];
-                self.describe_field_from_ty(&local.ty, field, None)
-            }
-            PlaceRef {
-                base: PlaceBase::Static(static_),
-                projection: [],
-            } =>
-                self.describe_field_from_ty(&static_.ty, field, None),
-            PlaceRef {
-                base,
-                projection: [proj_base @ .., elem],
-            } => match elem {
-                ProjectionElem::Deref => {
-                    self.describe_field(PlaceRef {
-                        base,
-                        projection: proj_base,
-                    }, field)
-                }
-                ProjectionElem::Downcast(_, variant_index) => {
-                    let base_ty = Place::ty_from(
-                        place.base,
-                        place.projection,
-                        *self.body,
-                        self.infcx.tcx).ty;
-                    self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
-                }
-                ProjectionElem::Field(_, field_type) => {
-                    self.describe_field_from_ty(&field_type, field, None)
-                }
-                ProjectionElem::Index(..)
-                | ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Subslice { .. } => {
-                    self.describe_field(PlaceRef {
-                        base,
-                        projection: proj_base,
-                    }, field)
-                }
-            },
-        }
-    }
-
-    /// End-user visible description of the `field_index`nth field of `ty`
-    fn describe_field_from_ty(
-        &self,
-        ty: Ty<'_>,
-        field: Field,
-        variant_index: Option<VariantIdx>
-    ) -> String {
-        if ty.is_box() {
-            // If the type is a box, the field is described from the boxed type
-            self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
-        } else {
-            match ty.kind {
-                ty::Adt(def, _) => {
-                    let variant = if let Some(idx) = variant_index {
-                        assert!(def.is_enum());
-                        &def.variants[idx]
-                    } else {
-                        def.non_enum_variant()
-                    };
-                    variant.fields[field.index()]
-                        .ident
-                        .to_string()
-                },
-                ty::Tuple(_) => field.index().to_string(),
-                ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
-                    self.describe_field_from_ty(&ty, field, variant_index)
-                }
-                ty::Array(ty, _) | ty::Slice(ty) =>
-                    self.describe_field_from_ty(&ty, field, variant_index),
-                ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
-                    // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case
-                    // the closure comes from another crate. But in that case we wouldn't
-                    // be borrowck'ing it, so we can just unwrap:
-                    let (&var_id, _) = self.infcx.tcx.upvars(def_id).unwrap()
-                        .get_index(field.index()).unwrap();
-
-                    self.infcx.tcx.hir().name(var_id).to_string()
-                }
-                _ => {
-                    // Might need a revision when the fields in trait RFC is implemented
-                    // (https://github.com/rust-lang/rfcs/pull/1546)
-                    bug!(
-                        "End-user description not implemented for field access on `{:?}`",
-                        ty
-                    );
-                }
-            }
-        }
-    }
-
-    /// Add a note that a type does not implement `Copy`
-    pub(super) fn note_type_does_not_implement_copy(
-        &self,
-        err: &mut DiagnosticBuilder<'a>,
-        place_desc: &str,
-        ty: Ty<'tcx>,
-        span: Option<Span>,
-    ) {
-        let message = format!(
-            "move occurs because {} has type `{}`, which does not implement the `Copy` trait",
-            place_desc,
-            ty,
-        );
-        if let Some(span) = span {
-            err.span_label(span, message);
-        } else {
-            err.note(&message);
-        }
-    }
-
-    pub(super) fn borrowed_content_source(
-        &self,
-        deref_base: PlaceRef<'cx, 'tcx>,
-    ) -> BorrowedContentSource<'tcx> {
-        let tcx = self.infcx.tcx;
-
-        // Look up the provided place and work out the move path index for it,
-        // we'll use this to check whether it was originally from an overloaded
-        // operator.
-        match self.move_data.rev_lookup.find(deref_base) {
-            LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
-                debug!("borrowed_content_source: mpi={:?}", mpi);
-
-                for i in &self.move_data.init_path_map[mpi] {
-                    let init = &self.move_data.inits[*i];
-                    debug!("borrowed_content_source: init={:?}", init);
-                    // We're only interested in statements that initialized a value, not the
-                    // initializations from arguments.
-                    let loc = match init.location {
-                        InitLocation::Statement(stmt) => stmt,
-                        _ => continue,
-                    };
-
-                    let bbd = &self.body[loc.block];
-                    let is_terminator = bbd.statements.len() == loc.statement_index;
-                    debug!(
-                        "borrowed_content_source: loc={:?} is_terminator={:?}",
-                        loc,
-                        is_terminator,
-                    );
-                    if !is_terminator {
-                        continue;
-                    } else if let Some(Terminator {
-                        kind: TerminatorKind::Call {
-                            ref func,
-                            from_hir_call: false,
-                            ..
-                        },
-                        ..
-                    }) = bbd.terminator {
-                        if let Some(source) = BorrowedContentSource::from_call(
-                            func.ty(*self.body, tcx),
-                            tcx
-                        ) {
-                            return source;
-                        }
-                    }
-                }
-            }
-            // Base is a `static` so won't be from an overloaded operator
-            _ => (),
-        };
-
-        // If we didn't find an overloaded deref or index, then assume it's a
-        // built in deref and check the type of the base.
-        let base_ty = Place::ty_from(
-            deref_base.base,
-            deref_base.projection,
-            *self.body,
-            tcx
-        ).ty;
-        if base_ty.is_unsafe_ptr() {
-            BorrowedContentSource::DerefRawPointer
-        } else if base_ty.is_mutable_ptr() {
-            BorrowedContentSource::DerefMutableRef
-        } else {
-            BorrowedContentSource::DerefSharedRef
-        }
-    }
-}
-
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
-    /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
-    /// name where required.
-    pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
-        let mut s = String::new();
-        let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
-
-        // We need to add synthesized lifetimes where appropriate. We do
-        // this by hooking into the pretty printer and telling it to label the
-        // lifetimes without names with the value `'0`.
-        match ty.kind {
-            ty::Ref(ty::RegionKind::ReLateBound(_, br), _, _)
-            | ty::Ref(
-                ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
-                _,
-                _,
-            ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
-            _ => {}
-        }
-
-        let _ = ty.print(printer);
-        s
-    }
-
-    /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
-    /// synthesized lifetime name where required.
-    pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
-        let mut s = String::new();
-        let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
-
-        let region = match ty.kind {
-            ty::Ref(region, _, _) => {
-                match region {
-                    ty::RegionKind::ReLateBound(_, br)
-                    | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
-                        printer.region_highlight_mode.highlighting_bound_region(*br, counter)
-                    }
-                    _ => {}
-                }
-
-                region
-            }
-            _ => bug!("ty for annotation of borrow region is not a reference"),
-        };
-
-        let _ = region.print(printer);
-        s
-    }
-}
-
-// The span(s) associated to a use of a place.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum UseSpans {
-    // The access is caused by capturing a variable for a closure.
-    ClosureUse {
-        // This is true if the captured variable was from a generator.
-        generator_kind: Option<GeneratorKind>,
-        // The span of the args of the closure, including the `move` keyword if
-        // it's present.
-        args_span: Span,
-        // The span of the first use of the captured variable inside the closure.
-        var_span: Span,
-    },
-    // This access has a single span associated to it: common case.
-    OtherUse(Span),
-}
-
-impl UseSpans {
-    pub(super) fn args_or_use(self) -> Span {
-        match self {
-            UseSpans::ClosureUse {
-                args_span: span, ..
-            }
-            | UseSpans::OtherUse(span) => span,
-        }
-    }
-
-    pub(super) fn var_or_use(self) -> Span {
-        match self {
-            UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
-        }
-    }
-
-    pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
-        match self {
-            UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
-            _ => None,
-        }
-    }
-
-    // Add a span label to the arguments of the closure, if it exists.
-    pub(super) fn args_span_label(
-        self,
-        err: &mut DiagnosticBuilder<'_>,
-        message: impl Into<String>,
-    ) {
-        if let UseSpans::ClosureUse { args_span, .. } = self {
-            err.span_label(args_span, message);
-        }
-    }
-
-    // Add a span label to the use of the captured variable, if it exists.
-    pub(super) fn var_span_label(
-        self,
-        err: &mut DiagnosticBuilder<'_>,
-        message: impl Into<String>,
-    ) {
-        if let UseSpans::ClosureUse { var_span, .. } = self {
-            err.span_label(var_span, message);
-        }
-    }
-
-    /// Returns `false` if this place is not used in a closure.
-    pub(super) fn for_closure(&self) -> bool {
-        match *self {
-            UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
-            _ => false,
-        }
-    }
-
-    /// Returns `false` if this place is not used in a generator.
-    pub(super) fn for_generator(&self) -> bool {
-        match *self {
-            UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
-            _ => false,
-        }
-    }
-
-    /// Describe the span associated with a use of a place.
-    pub(super) fn describe(&self) -> String {
-        match *self {
-            UseSpans::ClosureUse { generator_kind, .. } => if generator_kind.is_some() {
-                " in generator".to_string()
-            } else {
-                " in closure".to_string()
-            },
-            _ => "".to_string(),
-        }
-    }
-
-    pub(super) fn or_else<F>(self, if_other: F) -> Self
-    where
-        F: FnOnce() -> Self,
-    {
-        match self {
-            closure @ UseSpans::ClosureUse { .. } => closure,
-            UseSpans::OtherUse(_) => if_other(),
-        }
-    }
-}
-
-pub(super) enum BorrowedContentSource<'tcx> {
-    DerefRawPointer,
-    DerefMutableRef,
-    DerefSharedRef,
-    OverloadedDeref(Ty<'tcx>),
-    OverloadedIndex(Ty<'tcx>),
-}
-
-impl BorrowedContentSource<'tcx> {
-    pub(super) fn describe_for_unnamed_place(&self) -> String {
-        match *self {
-            BorrowedContentSource::DerefRawPointer => format!("a raw pointer"),
-            BorrowedContentSource::DerefSharedRef => format!("a shared reference"),
-            BorrowedContentSource::DerefMutableRef => {
-                format!("a mutable reference")
-            }
-            BorrowedContentSource::OverloadedDeref(ty) => {
-                if ty.is_rc() {
-                   format!("an `Rc`")
-                } else if ty.is_arc() {
-                    format!("an `Arc`")
-                } else {
-                    format!("dereference of `{}`", ty)
-                }
-            }
-            BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
-        }
-    }
-
-    pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
-        match *self {
-            BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
-            BorrowedContentSource::DerefSharedRef => Some("shared reference"),
-            BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
-            // Overloaded deref and index operators should be evaluated into a
-            // temporary. So we don't need a description here.
-            BorrowedContentSource::OverloadedDeref(_)
-            | BorrowedContentSource::OverloadedIndex(_) => None
-        }
-    }
-
-    pub(super) fn describe_for_immutable_place(&self) -> String {
-        match *self {
-            BorrowedContentSource::DerefRawPointer => format!("a `*const` pointer"),
-            BorrowedContentSource::DerefSharedRef => format!("a `&` reference"),
-            BorrowedContentSource::DerefMutableRef => {
-                 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
-            },
-            BorrowedContentSource::OverloadedDeref(ty) => {
-                if ty.is_rc() {
-                   format!("an `Rc`")
-                } else if ty.is_arc() {
-                    format!("an `Arc`")
-                } else {
-                    format!("a dereference of `{}`", ty)
-                }
-            }
-            BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
-        }
-    }
-
-    fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
-        match func.kind {
-            ty::FnDef(def_id, substs) => {
-                let trait_id = tcx.trait_of_item(def_id)?;
-
-                let lang_items = tcx.lang_items();
-                if Some(trait_id) == lang_items.deref_trait()
-                    || Some(trait_id) == lang_items.deref_mut_trait()
-                {
-                    Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
-                } else if Some(trait_id) == lang_items.index_trait()
-                    || Some(trait_id) == lang_items.index_mut_trait()
-                {
-                    Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        }
-    }
-}
-
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
-    /// Finds the spans associated to a move or copy of move_place at location.
-    pub(super) fn move_spans(
-        &self,
-        moved_place: PlaceRef<'cx, 'tcx>, // Could also be an upvar.
-        location: Location,
-    ) -> UseSpans {
-        use self::UseSpans::*;
-
-        let stmt = match self.body[location.block].statements.get(location.statement_index) {
-            Some(stmt) => stmt,
-            None => return OtherUse(self.body.source_info(location).span),
-        };
-
-        debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
-        if let  StatementKind::Assign(
-            box(_, Rvalue::Aggregate(ref kind, ref places))
-        ) = stmt.kind {
-            let def_id = match kind {
-                box AggregateKind::Closure(def_id, _)
-                | box AggregateKind::Generator(def_id, _, _) => def_id,
-                _ => return OtherUse(stmt.source_info.span),
-            };
-
-            debug!(
-                "move_spans: def_id={:?} places={:?}",
-                def_id, places
-            );
-            if let Some((args_span, generator_kind, var_span))
-                = self.closure_span(*def_id, moved_place, places) {
-                return ClosureUse {
-                    generator_kind,
-                    args_span,
-                    var_span,
-                };
-            }
-        }
-
-        OtherUse(stmt.source_info.span)
-    }
-
-    /// Finds the span of arguments of a closure (within `maybe_closure_span`)
-    /// and its usage of the local assigned at `location`.
-    /// This is done by searching in statements succeeding `location`
-    /// and originating from `maybe_closure_span`.
-    pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
-        use self::UseSpans::*;
-        debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
-
-        let target = match self.body[location.block]
-            .statements
-            .get(location.statement_index)
-        {
-            Some(&Statement {
-                kind: StatementKind::Assign(box(ref place, _)),
-                ..
-            }) => {
-                if let Some(local) = place.as_local() {
-                    local
-                } else {
-                    return OtherUse(use_span);
-                }
-            }
-            _ => return OtherUse(use_span),
-        };
-
-        if self.body.local_kind(target) != LocalKind::Temp {
-            // operands are always temporaries.
-            return OtherUse(use_span);
-        }
-
-        for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
-            if let StatementKind::Assign(
-                box(_, Rvalue::Aggregate(ref kind, ref places))
-            ) = stmt.kind {
-                let (def_id, is_generator) = match kind {
-                    box AggregateKind::Closure(def_id, _) => (def_id, false),
-                    box AggregateKind::Generator(def_id, _, _) => (def_id, true),
-                    _ => continue,
-                };
-
-                debug!(
-                    "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
-                    def_id, is_generator, places
-                );
-                if let Some((args_span, generator_kind, var_span)) = self.closure_span(
-                    *def_id, Place::from(target).as_ref(), places
-                ) {
-                    return ClosureUse {
-                        generator_kind,
-                        args_span,
-                        var_span,
-                    };
-                } else {
-                    return OtherUse(use_span);
-                }
-            }
-
-            if use_span != stmt.source_info.span {
-                break;
-            }
-        }
-
-        OtherUse(use_span)
-    }
-
-    /// Finds the span of a captured variable within a closure or generator.
-    fn closure_span(
-        &self,
-        def_id: DefId,
-        target_place: PlaceRef<'cx, 'tcx>,
-        places: &Vec<Operand<'tcx>>,
-    ) -> Option<(Span, Option<GeneratorKind>, Span)> {
-        debug!(
-            "closure_span: def_id={:?} target_place={:?} places={:?}",
-            def_id, target_place, places
-        );
-        let hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id)?;
-        let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
-        debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
-        if let hir::ExprKind::Closure(
-            .., body_id, args_span, _
-        ) = expr {
-            for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) {
-                match place {
-                    Operand::Copy(place) |
-                    Operand::Move(place) if target_place == place.as_ref() => {
-                        debug!("closure_span: found captured local {:?}", place);
-                        let body = self.infcx.tcx.hir().body(*body_id);
-                        let generator_kind = body.generator_kind();
-                        return Some((*args_span, generator_kind, upvar.span));
-                    },
-                    _ => {}
-                }
-            }
-
-        }
-        None
-    }
-
-    /// Helper to retrieve span(s) of given borrow from the current MIR
-    /// representation
-    pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
-        let span = self.body.source_info(borrow.reserve_location).span;
-        self.borrow_spans(span, borrow.reserve_location)
-    }
-}
index bacff0b3e54d2eb446faf00e850351ffbb9d92ef..a1932b551c144cff7965e23fcd5ca789db8c912f 100644 (file)
 use self::location::LocationTable;
 use self::prefixes::PrefixSet;
 use self::MutateMode::{JustWrite, WriteAndRead};
-use self::mutability_errors::AccessKind;
+use self::diagnostics::AccessKind;
 
 use self::path_utils::*;
 
 crate mod borrow_set;
-mod error_reporting;
+mod diagnostics;
 mod flows;
 mod location;
-mod conflict_errors;
-mod move_errors;
-mod mutability_errors;
 mod path_utils;
 crate mod place_ext;
 crate mod places_conflict;
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
deleted file mode 100644 (file)
index fd77976..0000000
+++ /dev/null
@@ -1,587 +0,0 @@
-use rustc::mir::*;
-use rustc::ty;
-use rustc_errors::{DiagnosticBuilder,Applicability};
-use syntax_pos::Span;
-
-use crate::borrow_check::MirBorrowckCtxt;
-use crate::borrow_check::prefixes::PrefixSet;
-use crate::borrow_check::error_reporting::UseSpans;
-use crate::dataflow::move_paths::{
-    IllegalMoveOrigin, IllegalMoveOriginKind,
-    LookupResult, MoveError, MovePathIndex,
-};
-
-// Often when desugaring a pattern match we may have many individual moves in
-// MIR that are all part of one operation from the user's point-of-view. For
-// example:
-//
-// let (x, y) = foo()
-//
-// would move x from the 0 field of some temporary, and y from the 1 field. We
-// group such errors together for cleaner error reporting.
-//
-// Errors are kept separate if they are from places with different parent move
-// paths. For example, this generates two errors:
-//
-// let (&x, &y) = (&String::new(), &String::new());
-#[derive(Debug)]
-enum GroupedMoveError<'tcx> {
-    // Place expression can't be moved from,
-    // e.g., match x[0] { s => (), } where x: &[String]
-    MovesFromPlace {
-        original_path: Place<'tcx>,
-        span: Span,
-        move_from: Place<'tcx>,
-        kind: IllegalMoveOriginKind<'tcx>,
-        binds_to: Vec<Local>,
-    },
-    // Part of a value expression can't be moved from,
-    // e.g., match &String::new() { &x => (), }
-    MovesFromValue {
-        original_path: Place<'tcx>,
-        span: Span,
-        move_from: MovePathIndex,
-        kind: IllegalMoveOriginKind<'tcx>,
-        binds_to: Vec<Local>,
-    },
-    // Everything that isn't from pattern matching.
-    OtherIllegalMove {
-        original_path: Place<'tcx>,
-        use_spans: UseSpans,
-        kind: IllegalMoveOriginKind<'tcx>,
-    },
-}
-
-impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
-    pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
-        let grouped_errors = self.group_move_errors(move_errors);
-        for error in grouped_errors {
-            self.report(error);
-        }
-    }
-
-    fn group_move_errors(
-        &self,
-        errors: Vec<(Place<'tcx>, MoveError<'tcx>)>
-    ) -> Vec<GroupedMoveError<'tcx>> {
-        let mut grouped_errors = Vec::new();
-        for (original_path, error) in errors {
-            self.append_to_grouped_errors(&mut grouped_errors, original_path, error);
-        }
-        grouped_errors
-    }
-
-    fn append_to_grouped_errors(
-        &self,
-        grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
-        original_path: Place<'tcx>,
-        error: MoveError<'tcx>,
-    ) {
-        match error {
-            MoveError::UnionMove { .. } => {
-                unimplemented!("don't know how to report union move errors yet.")
-            }
-            MoveError::IllegalMove {
-                cannot_move_out_of: IllegalMoveOrigin { location, kind },
-            } => {
-                // Note: that the only time we assign a place isn't a temporary
-                // to a user variable is when initializing it.
-                // If that ever stops being the case, then the ever initialized
-                // flow could be used.
-                if let Some(StatementKind::Assign(
-                    box(place, Rvalue::Use(Operand::Move(move_from)))
-                )) = self.body.basic_blocks()[location.block]
-                    .statements
-                    .get(location.statement_index)
-                    .map(|stmt| &stmt.kind)
-                {
-                    if let Some(local) = place.as_local() {
-                        let local_decl = &self.body.local_decls[local];
-                        // opt_match_place is the
-                        // match_span is the span of the expression being matched on
-                        // match *x.y { ... }        match_place is Some(*x.y)
-                        //       ^^^^                match_span is the span of *x.y
-                        //
-                        // opt_match_place is None for let [mut] x = ... statements,
-                        // whether or not the right-hand side is a place expression
-                        if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                            VarBindingForm {
-                                opt_match_place: Some((ref opt_match_place, match_span)),
-                                binding_mode: _,
-                                opt_ty_info: _,
-                                pat_span: _,
-                            },
-                        ))) = local_decl.local_info {
-                            let stmt_source_info = self.body.source_info(location);
-                            self.append_binding_error(
-                                grouped_errors,
-                                kind,
-                                original_path,
-                                move_from,
-                                local,
-                                opt_match_place,
-                                match_span,
-                                stmt_source_info.span,
-                            );
-                            return;
-                        }
-                    }
-                }
-
-                let move_spans = self.move_spans(original_path.as_ref(), location);
-                grouped_errors.push(GroupedMoveError::OtherIllegalMove {
-                    use_spans: move_spans,
-                    original_path,
-                    kind,
-                });
-            }
-        }
-    }
-
-    fn append_binding_error(
-        &self,
-        grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
-        kind: IllegalMoveOriginKind<'tcx>,
-        original_path: Place<'tcx>,
-        move_from: &Place<'tcx>,
-        bind_to: Local,
-        match_place: &Option<Place<'tcx>>,
-        match_span: Span,
-        statement_span: Span,
-    ) {
-        debug!(
-            "append_binding_error(match_place={:?}, match_span={:?})",
-            match_place, match_span
-        );
-
-        let from_simple_let = match_place.is_none();
-        let match_place = match_place.as_ref().unwrap_or(move_from);
-
-        match self.move_data.rev_lookup.find(match_place.as_ref()) {
-            // Error with the match place
-            LookupResult::Parent(_) => {
-                for ge in &mut *grouped_errors {
-                    if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge {
-                        if match_span == *span {
-                            debug!("appending local({:?}) to list", bind_to);
-                            if !binds_to.is_empty() {
-                                binds_to.push(bind_to);
-                            }
-                            return;
-                        }
-                    }
-                }
-                debug!("found a new move error location");
-
-                // Don't need to point to x in let x = ... .
-                let (binds_to, span) = if from_simple_let {
-                    (vec![], statement_span)
-                } else {
-                    (vec![bind_to], match_span)
-                };
-                grouped_errors.push(GroupedMoveError::MovesFromPlace {
-                    span,
-                    move_from: match_place.clone(),
-                    original_path,
-                    kind,
-                    binds_to,
-                });
-            }
-            // Error with the pattern
-            LookupResult::Exact(_) => {
-                let mpi = match self.move_data.rev_lookup.find(move_from.as_ref()) {
-                    LookupResult::Parent(Some(mpi)) => mpi,
-                    // move_from should be a projection from match_place.
-                    _ => unreachable!("Probably not unreachable..."),
-                };
-                for ge in &mut *grouped_errors {
-                    if let GroupedMoveError::MovesFromValue {
-                        span,
-                        move_from: other_mpi,
-                        binds_to,
-                        ..
-                    } = ge
-                    {
-                        if match_span == *span && mpi == *other_mpi {
-                            debug!("appending local({:?}) to list", bind_to);
-                            binds_to.push(bind_to);
-                            return;
-                        }
-                    }
-                }
-                debug!("found a new move error location");
-                grouped_errors.push(GroupedMoveError::MovesFromValue {
-                    span: match_span,
-                    move_from: mpi,
-                    original_path,
-                    kind,
-                    binds_to: vec![bind_to],
-                });
-            }
-        };
-    }
-
-    fn report(&mut self, error: GroupedMoveError<'tcx>) {
-        let (mut err, err_span) = {
-            let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
-                match error {
-                    GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
-                    GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
-                        (span, original_path, kind)
-                    }
-                    GroupedMoveError::OtherIllegalMove {
-                        use_spans,
-                        ref original_path,
-                        ref kind
-                    } => {
-                        (use_spans.args_or_use(), original_path, kind)
-                    },
-                };
-            debug!("report: original_path={:?} span={:?}, kind={:?} \
-                   original_path.is_upvar_field_projection={:?}", original_path, span, kind,
-                   self.is_upvar_field_projection(original_path.as_ref()));
-            (
-                match kind {
-                    IllegalMoveOriginKind::Static => {
-                        unreachable!();
-                    }
-                    IllegalMoveOriginKind::BorrowedContent { target_place } => {
-                        self.report_cannot_move_from_borrowed_content(
-                            original_path,
-                            target_place,
-                            span,
-                        )
-                    }
-                    IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
-                        self.cannot_move_out_of_interior_of_drop(span, ty)
-                    }
-                    IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
-                        self.cannot_move_out_of_interior_noncopy(
-                            span, ty, Some(*is_index),
-                        ),
-                },
-                span,
-            )
-        };
-
-        self.add_move_hints(error, &mut err, err_span);
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    fn report_cannot_move_from_static(
-        &mut self,
-        place: &Place<'tcx>,
-        span: Span
-    ) -> DiagnosticBuilder<'a> {
-        let description = if place.projection.len() == 1 {
-            format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
-        } else {
-            let base_static = PlaceRef {
-                base: &place.base,
-                projection: &[ProjectionElem::Deref],
-            };
-
-            format!(
-                "`{:?}` as `{:?}` is a static item",
-                self.describe_place(place.as_ref()).unwrap(),
-                self.describe_place(base_static).unwrap(),
-            )
-        };
-
-        self.cannot_move_out_of(span, &description)
-    }
-
-    fn report_cannot_move_from_borrowed_content(
-        &mut self,
-        move_place: &Place<'tcx>,
-        deref_target_place: &Place<'tcx>,
-        span: Span,
-    ) -> DiagnosticBuilder<'a> {
-        // Inspect the type of the content behind the
-        // borrow to provide feedback about why this
-        // was a move rather than a copy.
-        let ty = deref_target_place.ty(*self.body, self.infcx.tcx).ty;
-        let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
-            .find_map(|p| self.is_upvar_field_projection(p));
-
-        let deref_base = match deref_target_place.projection.as_ref() {
-            &[ref proj_base @ .., ProjectionElem::Deref] => {
-                PlaceRef {
-                    base: &deref_target_place.base,
-                    projection: &proj_base,
-                }
-            }
-            _ => bug!("deref_target_place is not a deref projection"),
-        };
-
-        if let PlaceRef {
-            base: PlaceBase::Local(local),
-            projection: [],
-        } = deref_base {
-            let decl = &self.body.local_decls[*local];
-            if decl.is_ref_for_guard() {
-                let mut err = self.cannot_move_out_of(
-                    span,
-                    &format!("`{}` in pattern guard", self.local_names[*local].unwrap()),
-                );
-                err.note(
-                    "variables bound in patterns cannot be moved from \
-                     until after the end of the pattern guard");
-                return err;
-            } else if decl.is_ref_to_static() {
-                return self.report_cannot_move_from_static(move_place, span);
-            }
-        }
-
-        debug!("report: ty={:?}", ty);
-        let mut err = match ty.kind {
-            ty::Array(..) | ty::Slice(..) =>
-                self.cannot_move_out_of_interior_noncopy(span, ty, None),
-            ty::Closure(def_id, closure_substs)
-                if def_id == self.mir_def_id && upvar_field.is_some()
-            => {
-                let closure_kind_ty = closure_substs
-                    .as_closure().kind_ty(def_id, self.infcx.tcx);
-                let closure_kind = closure_kind_ty.to_opt_closure_kind();
-                let capture_description = match closure_kind {
-                    Some(ty::ClosureKind::Fn) => {
-                        "captured variable in an `Fn` closure"
-                    }
-                    Some(ty::ClosureKind::FnMut) => {
-                        "captured variable in an `FnMut` closure"
-                    }
-                    Some(ty::ClosureKind::FnOnce) => {
-                        bug!("closure kind does not match first argument type")
-                    }
-                    None => bug!("closure kind not inferred by borrowck"),
-                };
-
-                let upvar = &self.upvars[upvar_field.unwrap().index()];
-                let upvar_hir_id = upvar.var_hir_id;
-                let upvar_name = upvar.name;
-                let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
-
-                let place_name = self.describe_place(move_place.as_ref()).unwrap();
-
-                let place_description = if self
-                    .is_upvar_field_projection(move_place.as_ref())
-                    .is_some()
-                {
-                    format!("`{}`, a {}", place_name, capture_description)
-                } else {
-                    format!(
-                        "`{}`, as `{}` is a {}",
-                        place_name,
-                        upvar_name,
-                        capture_description,
-                    )
-                };
-
-                debug!(
-                    "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",
-                    closure_kind_ty, closure_kind, place_description,
-                );
-
-                let mut diag = self.cannot_move_out_of(span, &place_description);
-
-                diag.span_label(upvar_span, "captured outer variable");
-
-                diag
-            }
-            _ => {
-                let source = self.borrowed_content_source(deref_base);
-                match (
-                    self.describe_place(move_place.as_ref()),
-                    source.describe_for_named_place(),
-                ) {
-                    (Some(place_desc), Some(source_desc)) => {
-                        self.cannot_move_out_of(
-                            span,
-                            &format!("`{}` which is behind a {}", place_desc, source_desc),
-                        )
-                    }
-                    (_, _) => {
-                        self.cannot_move_out_of(
-                            span,
-                            &source.describe_for_unnamed_place(),
-                        )
-                    }
-                }
-            },
-        };
-        let move_ty = format!(
-            "{:?}",
-            move_place.ty(*self.body, self.infcx.tcx).ty,
-        );
-        if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
-            let is_option = move_ty.starts_with("std::option::Option");
-            let is_result = move_ty.starts_with("std::result::Result");
-            if is_option || is_result {
-                err.span_suggestion(
-                    span,
-                    &format!("consider borrowing the `{}`'s content", if is_option {
-                        "Option"
-                    } else {
-                        "Result"
-                    }),
-                    format!("{}.as_ref()", snippet),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        }
-        err
-    }
-
-    fn add_move_hints(
-        &self,
-        error: GroupedMoveError<'tcx>,
-        err: &mut DiagnosticBuilder<'a>,
-        span: Span,
-    ) {
-        match error {
-            GroupedMoveError::MovesFromPlace {
-                mut binds_to,
-                move_from,
-                ..
-            } => {
-                if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
-                    err.span_suggestion(
-                        span,
-                        "consider borrowing here",
-                        format!("&{}", snippet),
-                        Applicability::Unspecified,
-                    );
-                }
-
-                if binds_to.is_empty() {
-                    let place_ty = move_from.ty(*self.body, self.infcx.tcx).ty;
-                    let place_desc = match self.describe_place(move_from.as_ref()) {
-                        Some(desc) => format!("`{}`", desc),
-                        None => format!("value"),
-                    };
-
-                    self.note_type_does_not_implement_copy(
-                        err,
-                        &place_desc,
-                        place_ty,
-                        Some(span)
-                    );
-                } else {
-                    binds_to.sort();
-                    binds_to.dedup();
-
-                    self.add_move_error_details(err, &binds_to);
-                }
-            }
-            GroupedMoveError::MovesFromValue { mut binds_to, .. } => {
-                binds_to.sort();
-                binds_to.dedup();
-                self.add_move_error_suggestions(err, &binds_to);
-                self.add_move_error_details(err, &binds_to);
-            }
-            // No binding. Nothing to suggest.
-            GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
-                let span = use_spans.var_or_use();
-                let place_ty = original_path.ty(*self.body, self.infcx.tcx).ty;
-                let place_desc = match self.describe_place(original_path.as_ref()) {
-                    Some(desc) => format!("`{}`", desc),
-                    None => format!("value"),
-                };
-                self.note_type_does_not_implement_copy(
-                    err,
-                    &place_desc,
-                    place_ty,
-                    Some(span),
-                );
-
-                use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
-                use_spans.var_span_label(
-                    err,
-                    format!("move occurs due to use{}", use_spans.describe()),
-                );
-            },
-        }
-    }
-
-    fn add_move_error_suggestions(
-        &self,
-        err: &mut DiagnosticBuilder<'a>,
-        binds_to: &[Local],
-    ) {
-        let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
-        for local in binds_to {
-            let bind_to = &self.body.local_decls[*local];
-            if let LocalInfo::User(
-                ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                    pat_span,
-                    ..
-                }))
-            ) = bind_to.local_info {
-                if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
-                {
-                    if pat_snippet.starts_with('&') {
-                        let pat_snippet = pat_snippet[1..].trim_start();
-                        let suggestion;
-                        let to_remove;
-                        if pat_snippet.starts_with("mut")
-                            && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
-                        {
-                            suggestion = pat_snippet["mut".len()..].trim_start();
-                            to_remove = "&mut";
-                        } else {
-                            suggestion = pat_snippet;
-                            to_remove = "&";
-                        }
-                        suggestions.push((
-                            pat_span,
-                            to_remove,
-                            suggestion.to_owned(),
-                        ));
-                    }
-                }
-            }
-        }
-        suggestions.sort_unstable_by_key(|&(span, _, _)| span);
-        suggestions.dedup_by_key(|&mut (span, _, _)| span);
-        for (span, to_remove, suggestion) in suggestions {
-            err.span_suggestion(
-                span,
-                &format!("consider removing the `{}`", to_remove),
-                suggestion,
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    fn add_move_error_details(
-        &self,
-        err: &mut DiagnosticBuilder<'a>,
-        binds_to: &[Local],
-    ) {
-        for (j, local) in binds_to.into_iter().enumerate() {
-            let bind_to = &self.body.local_decls[*local];
-            let binding_span = bind_to.source_info.span;
-
-            if j == 0 {
-                err.span_label(binding_span, "data moved here");
-            } else {
-                err.span_label(binding_span, "...and here");
-            }
-
-            if binds_to.len() == 1 {
-                self.note_type_does_not_implement_copy(
-                    err,
-                    &format!("`{}`", self.local_names[*local].unwrap()),
-                    bind_to.ty,
-                    Some(binding_span)
-                );
-            }
-        }
-
-        if binds_to.len() > 1 {
-            err.note("move occurs because these variables have types that \
-                      don't implement the `Copy` trait",
-            );
-        }
-    }
-}
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
deleted file mode 100644 (file)
index 98a7b10..0000000
+++ /dev/null
@@ -1,656 +0,0 @@
-use rustc::hir;
-use rustc::hir::Node;
-use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyCache};
-use rustc::mir::{Mutability, Place, PlaceRef, PlaceBase, ProjectionElem};
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc_index::vec::Idx;
-use syntax_pos::Span;
-use syntax_pos::symbol::kw;
-
-use crate::borrow_check::MirBorrowckCtxt;
-use crate::borrow_check::error_reporting::BorrowedContentSource;
-use crate::util::collect_writes::FindAssignments;
-use rustc_errors::Applicability;
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub(super) enum AccessKind {
-    MutableBorrow,
-    Mutate,
-}
-
-impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
-    pub(super) fn report_mutability_error(
-        &mut self,
-        access_place: &Place<'tcx>,
-        span: Span,
-        the_place_err: PlaceRef<'cx, 'tcx>,
-        error_access: AccessKind,
-        location: Location,
-    ) {
-        debug!(
-            "report_mutability_error(\
-                access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\
-            )",
-            access_place, span, the_place_err, error_access, location,
-        );
-
-        let mut err;
-        let item_msg;
-        let reason;
-        let mut opt_source = None;
-        let access_place_desc = self.describe_place(access_place.as_ref());
-        debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
-
-        match the_place_err {
-            PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [],
-            } => {
-                item_msg = format!("`{}`", access_place_desc.unwrap());
-                if access_place.as_local().is_some() {
-                    reason = ", as it is not declared as mutable".to_string();
-                } else {
-                    let name = self.local_names[*local]
-                        .expect("immutable unnamed local");
-                    reason = format!(", as `{}` is not declared as mutable", name);
-                }
-            }
-
-            PlaceRef {
-                base: _,
-                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
-            } => {
-                debug_assert!(is_closure_or_generator(
-                    Place::ty_from(
-                        &the_place_err.base,
-                        proj_base,
-                        *self.body,
-                        self.infcx.tcx
-                    ).ty));
-
-                item_msg = format!("`{}`", access_place_desc.unwrap());
-                if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
-                    reason = ", as it is not declared as mutable".to_string();
-                } else {
-                    let name = self.upvars[upvar_index.index()].name;
-                    reason = format!(", as `{}` is not declared as mutable", name);
-                }
-            }
-
-            PlaceRef {
-                base: &PlaceBase::Local(local),
-                projection: [ProjectionElem::Deref],
-            } if self.body.local_decls[local].is_ref_for_guard() => {
-                item_msg = format!("`{}`", access_place_desc.unwrap());
-                reason = ", as it is immutable for the pattern guard".to_string();
-            }
-            PlaceRef {
-                base: &PlaceBase::Local(local),
-                projection: [ProjectionElem::Deref],
-            } if self.body.local_decls[local].is_ref_to_static() => {
-                if access_place.projection.len() == 1 {
-                    item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
-                    reason = String::new();
-                } else {
-                    item_msg = format!("`{}`", access_place_desc.unwrap());
-                    let local_info = &self.body.local_decls[local].local_info;
-                    if let LocalInfo::StaticRef { def_id, .. } = *local_info {
-                        let static_name = &self.infcx.tcx.item_name(def_id);
-                        reason = format!(", as `{}` is an immutable static item", static_name);
-                    } else {
-                        bug!("is_ref_to_static return true, but not ref to static?");
-                    }
-                }
-            }
-            PlaceRef {
-                base: _,
-                projection: [proj_base @ .., ProjectionElem::Deref],
-            } => {
-                if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
-                    proj_base.is_empty() &&
-                    !self.upvars.is_empty() {
-                    item_msg = format!("`{}`", access_place_desc.unwrap());
-                    debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
-                    debug_assert!(is_closure_or_generator(
-                        Place::ty_from(
-                            the_place_err.base,
-                            the_place_err.projection,
-                            *self.body,
-                            self.infcx.tcx
-                        )
-                        .ty
-                    ));
-
-                    reason =
-                        if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
-                            ", as it is a captured variable in a `Fn` closure".to_string()
-                        } else {
-                            ", as `Fn` closures cannot mutate their captured variables".to_string()
-                        }
-                } else {
-                    let source = self.borrowed_content_source(PlaceRef {
-                        base: the_place_err.base,
-                        projection: proj_base,
-                    });
-                    let pointer_type = source.describe_for_immutable_place();
-                    opt_source = Some(source);
-                    if let Some(desc) = access_place_desc {
-                        item_msg = format!("`{}`", desc);
-                        reason = match error_access {
-                            AccessKind::Mutate => format!(" which is behind {}", pointer_type),
-                            AccessKind::MutableBorrow => {
-                                format!(", as it is behind {}", pointer_type)
-                            }
-                        }
-                    } else {
-                        item_msg = format!("data in {}", pointer_type);
-                        reason = String::new();
-                    }
-                }
-            }
-
-            PlaceRef {
-                base: PlaceBase::Static(_),
-                ..
-            }
-            | PlaceRef {
-                base: _,
-                projection: [.., ProjectionElem::Index(_)],
-            }
-            | PlaceRef {
-                base: _,
-                projection: [.., ProjectionElem::ConstantIndex { .. }],
-            }
-            | PlaceRef {
-                base: _,
-                projection: [.., ProjectionElem::Subslice { .. }],
-            }
-            | PlaceRef {
-                base: _,
-                projection: [.., ProjectionElem::Downcast(..)],
-            } => bug!("Unexpected immutable place."),
-        }
-
-        debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason);
-
-        // `act` and `acted_on` are strings that let us abstract over
-        // the verbs used in some diagnostic messages.
-        let act;
-        let acted_on;
-
-        let span = match error_access {
-            AccessKind::Mutate => {
-                err = self.cannot_assign(span, &(item_msg + &reason));
-                act = "assign";
-                acted_on = "written";
-                span
-            }
-            AccessKind::MutableBorrow => {
-                act = "borrow as mutable";
-                acted_on = "borrowed as mutable";
-
-                let borrow_spans = self.borrow_spans(span, location);
-                let borrow_span = borrow_spans.args_or_use();
-                err = self.cannot_borrow_path_as_mutable_because(
-                    borrow_span,
-                    &item_msg,
-                    &reason,
-                );
-                borrow_spans.var_span_label(
-                    &mut err,
-                    format!(
-                        "mutable borrow occurs due to use of `{}` in closure",
-                        // always Some() if the message is printed.
-                        self.describe_place(access_place.as_ref()).unwrap_or_default(),
-                    )
-                );
-                borrow_span
-            }
-        };
-
-        debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
-
-        match the_place_err {
-            // Suggest making an existing shared borrow in a struct definition a mutable borrow.
-            //
-            // This is applicable when we have a deref of a field access to a deref of a local -
-            // something like `*((*_1).0`. The local that we get will be a reference to the
-            // struct we've got a field access of (it must be a reference since there's a deref
-            // after the field access).
-            PlaceRef {
-                base,
-                projection: [proj_base @ ..,
-                             ProjectionElem::Deref,
-                             ProjectionElem::Field(field, _),
-                             ProjectionElem::Deref,
-                ],
-            } => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-
-                if let Some((span, message)) = annotate_struct_field(
-                    self.infcx.tcx,
-                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty,
-                    field,
-                ) {
-                    err.span_suggestion(
-                        span,
-                        "consider changing this to be mutable",
-                        message,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            },
-
-            // Suggest removing a `&mut` from the use of a mutable reference.
-            PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [],
-            } if {
-                self.body.local_decls.get(*local).map(|local_decl| {
-                    if let LocalInfo::User(ClearCrossCrate::Set(
-                        mir::BindingForm::ImplicitSelf(kind)
-                    )) = local_decl.local_info {
-                        // Check if the user variable is a `&mut self` and we can therefore
-                        // suggest removing the `&mut`.
-                        //
-                        // Deliberately fall into this case for all implicit self types,
-                        // so that we don't fall in to the next case with them.
-                        kind == mir::ImplicitSelfKind::MutRef
-                    } else if Some(kw::SelfLower) == self.local_names[*local] {
-                        // Otherwise, check if the name is the self kewyord - in which case
-                        // we have an explicit self. Do the same thing in this case and check
-                        // for a `self: &mut Self` to suggest removing the `&mut`.
-                        if let ty::Ref(
-                            _, _, hir::Mutability::Mutable
-                        ) = local_decl.ty.kind {
-                            true
-                        } else {
-                            false
-                        }
-                    } else {
-                        false
-                    }
-                }).unwrap_or(false)
-            } => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-                err.span_label(span, "try removing `&mut` here");
-            },
-
-            // We want to suggest users use `let mut` for local (user
-            // variable) mutations...
-            PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [],
-            } if self.body.local_decls[*local].can_be_made_mutable() => {
-                // ... but it doesn't make sense to suggest it on
-                // variables that are `ref x`, `ref mut x`, `&self`,
-                // or `&mut self` (such variables are simply not
-                // mutable).
-                let local_decl = &self.body.local_decls[*local];
-                assert_eq!(local_decl.mutability, Mutability::Not);
-
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-                err.span_suggestion(
-                    local_decl.source_info.span,
-                    "consider changing this to be mutable",
-                    format!("mut {}", self.local_names[*local].unwrap()),
-                    Applicability::MachineApplicable,
-                );
-            }
-
-            // Also suggest adding mut for upvars
-            PlaceRef {
-                base,
-                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
-            } => {
-                debug_assert!(is_closure_or_generator(
-                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty
-                ));
-
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-
-                let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id;
-                if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
-                {
-                    if let hir::PatKind::Binding(
-                        hir::BindingAnnotation::Unannotated,
-                        _,
-                        upvar_ident,
-                        _,
-                    ) = pat.kind
-                    {
-                        err.span_suggestion(
-                            upvar_ident.span,
-                            "consider changing this to be mutable",
-                            format!("mut {}", upvar_ident.name),
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }
-            }
-
-            // complete hack to approximate old AST-borrowck
-            // diagnostic: if the span starts with a mutable borrow of
-            // a local variable, then just suggest the user remove it.
-            PlaceRef {
-                base: PlaceBase::Local(_),
-                projection: [],
-            } if {
-                    if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
-                        snippet.starts_with("&mut ")
-                    } else {
-                        false
-                    }
-                } =>
-            {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-                err.span_label(span, "try removing `&mut` here");
-            }
-
-            PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [ProjectionElem::Deref],
-            } if self.body.local_decls[*local].is_ref_for_guard() => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-                err.note(
-                    "variables bound in patterns are immutable until the end of the pattern guard",
-                );
-            }
-
-            // We want to point out when a `&` can be readily replaced
-            // with an `&mut`.
-            //
-            // FIXME: can this case be generalized to work for an
-            // arbitrary base for the projection?
-            PlaceRef {
-                base: PlaceBase::Local(local),
-                projection: [ProjectionElem::Deref],
-            } if self.body.local_decls[*local].is_user_variable() =>
-            {
-                let local_decl = &self.body.local_decls[*local];
-                let suggestion = match local_decl.local_info {
-                    LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_))) => {
-                        Some(suggest_ampmut_self(self.infcx.tcx, local_decl))
-                    }
-
-                    LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
-                        mir::VarBindingForm {
-                            binding_mode: ty::BindingMode::BindByValue(_),
-                            opt_ty_info,
-                            ..
-                        },
-                    ))) => Some(suggest_ampmut(
-                        self.infcx.tcx,
-                        self.body,
-                        *local,
-                        local_decl,
-                        opt_ty_info,
-                    )),
-
-                    LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
-                        mir::VarBindingForm {
-                            binding_mode: ty::BindingMode::BindByReference(_),
-                            ..
-                        },
-                    ))) => {
-                        let pattern_span = local_decl.source_info.span;
-                        suggest_ref_mut(self.infcx.tcx, pattern_span)
-                            .map(|replacement| (pattern_span, replacement))
-                    }
-
-                    LocalInfo::User(ClearCrossCrate::Clear) => bug!("saw cleared local state"),
-
-                    _ => unreachable!(),
-                };
-
-                let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() {
-                    ("&", "reference")
-                } else {
-                    ("*const", "pointer")
-                };
-
-                if let Some((err_help_span, suggested_code)) = suggestion {
-                    err.span_suggestion(
-                        err_help_span,
-                        &format!("consider changing this to be a mutable {}", pointer_desc),
-                        suggested_code,
-                        Applicability::MachineApplicable,
-                    );
-                }
-
-                match self.local_names[*local] {
-                    Some(name) if !local_decl.from_compiler_desugaring() => {
-                        err.span_label(
-                            span,
-                            format!(
-                                "`{NAME}` is a `{SIGIL}` {DESC}, \
-                                so the data it refers to cannot be {ACTED_ON}",
-                                NAME = name,
-                                SIGIL = pointer_sigil,
-                                DESC = pointer_desc,
-                                ACTED_ON = acted_on
-                            ),
-                        );
-                    }
-                    _ => {
-                        err.span_label(
-                            span,
-                            format!(
-                                "cannot {ACT} through `{SIGIL}` {DESC}",
-                                ACT = act,
-                                SIGIL = pointer_sigil,
-                                DESC = pointer_desc
-                            ),
-                        );
-                    }
-                }
-            }
-
-            PlaceRef {
-                base,
-                projection: [ProjectionElem::Deref],
-            // FIXME document what is this 1 magic number about
-            } if *base == PlaceBase::Local(Local::new(1)) &&
-                  !self.upvars.is_empty() =>
-            {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-                err.span_help(
-                    self.body.span,
-                    "consider changing this to accept closures that implement `FnMut`"
-                );
-            }
-
-            PlaceRef {
-                base: _,
-                projection: [.., ProjectionElem::Deref],
-            } => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-
-                match opt_source {
-                    Some(BorrowedContentSource::OverloadedDeref(ty)) => {
-                        err.help(
-                            &format!(
-                                "trait `DerefMut` is required to modify through a dereference, \
-                                but it is not implemented for `{}`",
-                                ty,
-                            ),
-                        );
-                    },
-                    Some(BorrowedContentSource::OverloadedIndex(ty)) => {
-                        err.help(
-                            &format!(
-                                "trait `IndexMut` is required to modify indexed content, \
-                                but it is not implemented for `{}`",
-                                ty,
-                            ),
-                        );
-                    }
-                    _ => (),
-                }
-            }
-
-            _ => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-            }
-        }
-
-        err.buffer(&mut self.errors_buffer);
-    }
-}
-
-fn suggest_ampmut_self<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    local_decl: &mir::LocalDecl<'tcx>,
-) -> (Span, String) {
-    let sp = local_decl.source_info.span;
-    (sp, match tcx.sess.source_map().span_to_snippet(sp) {
-        Ok(snippet) => {
-            let lt_pos = snippet.find('\'');
-            if let Some(lt_pos) = lt_pos {
-                format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
-            } else {
-                "&mut self".to_string()
-            }
-        }
-        _ => "&mut self".to_string()
-    })
-}
-
-// When we want to suggest a user change a local variable to be a `&mut`, there
-// are three potential "obvious" things to highlight:
-//
-// let ident [: Type] [= RightHandSideExpression];
-//     ^^^^^    ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
-//     (1.)     (2.)              (3.)
-//
-// We can always fallback on highlighting the first. But chances are good that
-// the user experience will be better if we highlight one of the others if possible;
-// for example, if the RHS is present and the Type is not, then the type is going to
-// be inferred *from* the RHS, which means we should highlight that (and suggest
-// that they borrow the RHS mutably).
-//
-// This implementation attempts to emulate AST-borrowck prioritization
-// by trying (3.), then (2.) and finally falling back on (1.).
-fn suggest_ampmut<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: ReadOnlyBodyCache<'_, 'tcx>,
-    local: Local,
-    local_decl: &mir::LocalDecl<'tcx>,
-    opt_ty_info: Option<Span>,
-) -> (Span, String) {
-    let locations = body.find_assignments(local);
-    if !locations.is_empty() {
-        let assignment_rhs_span = body.source_info(locations[0]).span;
-        if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
-            if let (true, Some(ws_pos)) = (
-                src.starts_with("&'"),
-                src.find(|c: char| -> bool { c.is_whitespace() }),
-            ) {
-                let lt_name = &src[1..ws_pos];
-                let ty = &src[ws_pos..];
-                return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
-            } else if src.starts_with('&') {
-                let borrowed_expr = &src[1..];
-                return (assignment_rhs_span, format!("&mut {}", borrowed_expr));
-            }
-        }
-    }
-
-    let highlight_span = match opt_ty_info {
-        // if this is a variable binding with an explicit type,
-        // try to highlight that for the suggestion.
-        Some(ty_span) => ty_span,
-
-        // otherwise, just highlight the span associated with
-        // the (MIR) LocalDecl.
-        None => local_decl.source_info.span,
-    };
-
-    if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) {
-        if let (true, Some(ws_pos)) = (
-            src.starts_with("&'"),
-            src.find(|c: char| -> bool { c.is_whitespace() }),
-        ) {
-            let lt_name = &src[1..ws_pos];
-            let ty = &src[ws_pos..];
-            return (highlight_span, format!("&{} mut{}", lt_name, ty));
-        }
-    }
-
-    let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
-    assert_eq!(ty_mut.mutbl, hir::Mutability::Immutable);
-    (highlight_span,
-     if local_decl.ty.is_region_ptr() {
-         format!("&mut {}", ty_mut.ty)
-     } else {
-         format!("*mut {}", ty_mut.ty)
-     })
-}
-
-fn is_closure_or_generator(ty: Ty<'_>) -> bool {
-    ty.is_closure() || ty.is_generator()
-}
-
-/// Adds a suggestion to a struct definition given a field access to a local.
-/// This function expects the local to be a reference to a struct in order to produce a suggestion.
-///
-/// ```text
-/// LL |     s: &'a String
-///    |        ---------- use `&'a mut String` here to make mutable
-/// ```
-fn annotate_struct_field(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-    field: &mir::Field,
-) -> Option<(Span, String)> {
-    // Expect our local to be a reference to a struct of some kind.
-    if let ty::Ref(_, ty, _) = ty.kind {
-        if let ty::Adt(def, _) = ty.kind {
-            let field = def.all_fields().nth(field.index())?;
-            // Use the HIR types to construct the diagnostic message.
-            let hir_id = tcx.hir().as_local_hir_id(field.did)?;
-            let node = tcx.hir().find(hir_id)?;
-            // Now we're dealing with the actual struct that we're going to suggest a change to,
-            // we can expect a field that is an immutable reference to a type.
-            if let hir::Node::Field(field) = node {
-                if let hir::TyKind::Rptr(lifetime, hir::MutTy {
-                    mutbl: hir::Mutability::Immutable,
-                    ref ty
-                }) = field.ty.kind {
-                    // Get the snippets in two parts - the named lifetime (if there is one) and
-                    // type being referenced, that way we can reconstruct the snippet without loss
-                    // of detail.
-                    let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
-                    let lifetime_snippet = if !lifetime.is_elided() {
-                        format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
-                    } else {
-                        String::new()
-                    };
-
-                    return Some((
-                        field.ty.span,
-                        format!(
-                            "&{}mut {}",
-                            lifetime_snippet, &*type_snippet,
-                        ),
-                    ));
-                }
-            }
-        }
-    }
-
-    None
-}
-
-/// If possible, suggest replacing `ref` with `ref mut`.
-fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option<String> {
-    let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?;
-    if hi_src.starts_with("ref")
-        && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace)
-    {
-        let replacement = format!("ref mut{}", &hi_src["ref".len()..]);
-        Some(replacement)
-    } else {
-        None
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
deleted file mode 100644 (file)
index 7ab0692..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-use std::collections::VecDeque;
-use std::rc::Rc;
-
-use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
-use crate::borrow_check::nll::ToRegionVid;
-use crate::util::liveness::{self, DefUse};
-use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
-use rustc::mir::{Local, Location, Body};
-use rustc::ty::{RegionVid, TyCtxt};
-use rustc_data_structures::fx::FxHashSet;
-
-crate fn find<'tcx>(
-    body: &Body<'tcx>,
-    regioncx: &Rc<RegionInferenceContext<'tcx>>,
-    tcx: TyCtxt<'tcx>,
-    region_vid: RegionVid,
-    start_point: Location,
-) -> Option<Cause> {
-    let mut uf = UseFinder {
-        body,
-        regioncx,
-        tcx,
-        region_vid,
-        start_point,
-    };
-
-    uf.find()
-}
-
-struct UseFinder<'cx, 'tcx> {
-    body: &'cx Body<'tcx>,
-    regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
-    tcx: TyCtxt<'tcx>,
-    region_vid: RegionVid,
-    start_point: Location,
-}
-
-impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
-    fn find(&mut self) -> Option<Cause> {
-        let mut queue = VecDeque::new();
-        let mut visited = FxHashSet::default();
-
-        queue.push_back(self.start_point);
-        while let Some(p) = queue.pop_front() {
-            if !self.regioncx.region_contains(self.region_vid, p) {
-                continue;
-            }
-
-            if !visited.insert(p) {
-                continue;
-            }
-
-            let block_data = &self.body[p.block];
-
-            match self.def_use(p, block_data.visitable(p.statement_index)) {
-                Some(DefUseResult::Def) => {}
-
-                Some(DefUseResult::UseLive { local }) => {
-                    return Some(Cause::LiveVar(local, p));
-                }
-
-                Some(DefUseResult::UseDrop { local }) => {
-                    return Some(Cause::DropVar(local, p));
-                }
-
-                None => {
-                    if p.statement_index < block_data.statements.len() {
-                        queue.push_back(p.successor_within_block());
-                    } else {
-                        queue.extend(
-                            block_data
-                                .terminator()
-                                .successors()
-                                .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind())
-                                .map(|&bb| Location {
-                                    statement_index: 0,
-                                    block: bb,
-                                }),
-                        );
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
-    fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option<DefUseResult> {
-        let mut visitor = DefUseVisitor {
-            body: self.body,
-            tcx: self.tcx,
-            region_vid: self.region_vid,
-            def_use_result: None,
-        };
-
-        thing.apply(location, &mut visitor);
-
-        visitor.def_use_result
-    }
-}
-
-struct DefUseVisitor<'cx, 'tcx> {
-    body: &'cx Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    region_vid: RegionVid,
-    def_use_result: Option<DefUseResult>,
-}
-
-enum DefUseResult {
-    Def,
-    UseLive { local: Local },
-    UseDrop { local: Local },
-}
-
-impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
-        let local_ty = self.body.local_decls[local].ty;
-
-        let mut found_it = false;
-        self.tcx.for_each_free_region(&local_ty, |r| {
-            if r.to_region_vid() == self.region_vid {
-                found_it = true;
-            }
-        });
-
-        if found_it {
-            self.def_use_result = match liveness::categorize(context) {
-                Some(DefUse::Def) => Some(DefUseResult::Def),
-                Some(DefUse::Use) => Some(DefUseResult::UseLive { local }),
-                Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }),
-                None => None,
-            };
-        }
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
deleted file mode 100644 (file)
index 43aabac..0000000
+++ /dev/null
@@ -1,669 +0,0 @@
-use std::collections::VecDeque;
-
-use crate::borrow_check::borrow_set::BorrowData;
-use crate::borrow_check::error_reporting::UseSpans;
-use crate::borrow_check::nll::region_infer::{Cause, RegionName};
-use crate::borrow_check::nll::ConstraintDescription;
-use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
-use rustc::mir::{
-    CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
-    Statement, StatementKind, TerminatorKind,
-};
-use rustc::ty::{self, TyCtxt};
-use rustc::ty::adjustment::{PointerCast};
-use rustc_index::vec::IndexVec;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::DiagnosticBuilder;
-use syntax_pos::Span;
-use syntax_pos::symbol::Symbol;
-
-mod find_use;
-
-#[derive(Debug)]
-pub(in crate::borrow_check) enum BorrowExplanation {
-    UsedLater(LaterUseKind, Span),
-    UsedLaterInLoop(LaterUseKind, Span),
-    UsedLaterWhenDropped {
-        drop_loc: Location,
-        dropped_local: Local,
-        should_note_order: bool,
-    },
-    MustBeValidFor {
-        category: ConstraintCategory,
-        from_closure: bool,
-        span: Span,
-        region_name: RegionName,
-        opt_place_desc: Option<String>,
-    },
-    Unexplained,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub(in crate::borrow_check) enum LaterUseKind {
-    TraitCapture,
-    ClosureCapture,
-    Call,
-    FakeLetRead,
-    Other,
-}
-
-impl BorrowExplanation {
-    pub(in crate::borrow_check) fn is_explained(&self) -> bool {
-        match self {
-            BorrowExplanation::Unexplained => false,
-            _ => true,
-        }
-    }
-    pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
-        local_names: &IndexVec<Local, Option<Symbol>>,
-        err: &mut DiagnosticBuilder<'_>,
-        borrow_desc: &str,
-        borrow_span: Option<Span>,
-    ) {
-        match *self {
-            BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
-                let message = match later_use_kind {
-                    LaterUseKind::TraitCapture => "captured here by trait object",
-                    LaterUseKind::ClosureCapture => "captured here by closure",
-                    LaterUseKind::Call => "used by call",
-                    LaterUseKind::FakeLetRead => "stored here",
-                    LaterUseKind::Other => "used here",
-                };
-                if !borrow_span.map(|sp| sp.overlaps(var_or_use_span)).unwrap_or(false) {
-                    err.span_label(
-                        var_or_use_span,
-                        format!("{}borrow later {}", borrow_desc, message),
-                    );
-                }
-            }
-            BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
-                let message = match later_use_kind {
-                    LaterUseKind::TraitCapture => {
-                        "borrow captured here by trait object, in later iteration of loop"
-                    }
-                    LaterUseKind::ClosureCapture => {
-                        "borrow captured here by closure, in later iteration of loop"
-                    }
-                    LaterUseKind::Call => "borrow used by call, in later iteration of loop",
-                    LaterUseKind::FakeLetRead => "borrow later stored here",
-                    LaterUseKind::Other => "borrow used here, in later iteration of loop",
-                };
-                err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
-            }
-            BorrowExplanation::UsedLaterWhenDropped {
-                drop_loc,
-                dropped_local,
-                should_note_order,
-            } => {
-                let local_decl = &body.local_decls[dropped_local];
-                let (dtor_desc, type_desc) = match local_decl.ty.kind {
-                    // If type is an ADT that implements Drop, then
-                    // simplify output by reporting just the ADT name.
-                    ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => (
-                        "`Drop` code",
-                        format!("type `{}`", tcx.def_path_str(adt.did)),
-                    ),
-
-                    // Otherwise, just report the whole type (and use
-                    // the intentionally fuzzy phrase "destructor")
-                    ty::Closure(..) => ("destructor", "closure".to_owned()),
-                    ty::Generator(..) => ("destructor", "generator".to_owned()),
-
-                    _ => ("destructor", format!("type `{}`", local_decl.ty)),
-                };
-
-                match local_names[dropped_local] {
-                    Some(local_name) if !local_decl.from_compiler_desugaring() => {
-                        let message = format!(
-                            "{B}borrow might be used here, when `{LOC}` is dropped \
-                             and runs the {DTOR} for {TYPE}",
-                            B = borrow_desc,
-                            LOC = local_name,
-                            TYPE = type_desc,
-                            DTOR = dtor_desc
-                        );
-                        err.span_label(body.source_info(drop_loc).span, message);
-
-                        if should_note_order {
-                            err.note(
-                                "values in a scope are dropped \
-                                 in the opposite order they are defined",
-                            );
-                        }
-                    }
-                    _ => {
-                        err.span_label(
-                            local_decl.source_info.span,
-                            format!(
-                                "a temporary with access to the {B}borrow \
-                                 is created here ...",
-                                B = borrow_desc
-                            ),
-                        );
-                        let message = format!(
-                            "... and the {B}borrow might be used here, \
-                             when that temporary is dropped \
-                             and runs the {DTOR} for {TYPE}",
-                            B = borrow_desc,
-                            TYPE = type_desc,
-                            DTOR = dtor_desc
-                        );
-                        err.span_label(body.source_info(drop_loc).span, message);
-
-                        if let Some(info) = &local_decl.is_block_tail {
-                            // FIXME: use span_suggestion instead, highlighting the
-                            // whole block tail expression.
-                            let msg = if info.tail_result_is_ignored {
-                                "The temporary is part of an expression at the end of a block. \
-                                 Consider adding semicolon after the expression so its temporaries \
-                                 are dropped sooner, before the local variables declared by the \
-                                 block are dropped."
-                            } else {
-                                "The temporary is part of an expression at the end of a block. \
-                                 Consider forcing this temporary to be dropped sooner, before \
-                                 the block's local variables are dropped. \
-                                 For example, you could save the expression's value in a new \
-                                 local variable `x` and then make `x` be the expression \
-                                 at the end of the block."
-                            };
-
-                            err.note(msg);
-                        }
-                    }
-                }
-            }
-            BorrowExplanation::MustBeValidFor {
-                category,
-                span,
-                ref region_name,
-                ref opt_place_desc,
-                from_closure: _,
-            } => {
-                region_name.highlight_region_name(err);
-
-                if let Some(desc) = opt_place_desc {
-                    err.span_label(
-                        span,
-                        format!(
-                            "{}requires that `{}` is borrowed for `{}`",
-                            category.description(),
-                            desc,
-                            region_name,
-                        ),
-                    );
-                } else {
-                    err.span_label(
-                        span,
-                        format!(
-                            "{}requires that {}borrow lasts for `{}`",
-                            category.description(),
-                            borrow_desc,
-                            region_name,
-                        ),
-                    );
-                };
-            }
-            _ => {}
-        }
-    }
-}
-
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
-    /// Returns structured explanation for *why* the borrow contains the
-    /// point from `location`. This is key for the "3-point errors"
-    /// [described in the NLL RFC][d].
-    ///
-    /// # Parameters
-    ///
-    /// - `borrow`: the borrow in question
-    /// - `location`: where the borrow occurs
-    /// - `kind_place`: if Some, this describes the statement that triggered the error.
-    ///   - first half is the kind of write, if any, being performed
-    ///   - second half is the place being accessed
-    ///
-    /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
-    pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
-        &self,
-        location: Location,
-        borrow: &BorrowData<'tcx>,
-        kind_place: Option<(WriteKind, &Place<'tcx>)>,
-    ) -> BorrowExplanation {
-        debug!(
-            "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
-            location, borrow, kind_place
-        );
-
-        let regioncx = &self.nonlexical_regioncx;
-        let body: &Body<'_> = &self.body;
-        let tcx = self.infcx.tcx;
-
-        let borrow_region_vid = borrow.region;
-        debug!(
-            "explain_why_borrow_contains_point: borrow_region_vid={:?}",
-            borrow_region_vid
-        );
-
-        let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, location);
-        debug!(
-            "explain_why_borrow_contains_point: region_sub={:?}",
-            region_sub
-        );
-
-        match find_use::find(body, regioncx, tcx, region_sub, location) {
-            Some(Cause::LiveVar(local, location)) => {
-                let span = body.source_info(location).span;
-                let spans = self
-                    .move_spans(Place::from(local).as_ref(), location)
-                    .or_else(|| self.borrow_spans(span, location));
-
-                let borrow_location = location;
-                if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
-                    let later_use = self.later_use_kind(borrow, spans, location);
-                    BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
-                } else {
-                    // Check if the location represents a `FakeRead`, and adapt the error
-                    // message to the `FakeReadCause` it is from: in particular,
-                    // the ones inserted in optimized `let var = <expr>` patterns.
-                    let later_use = self.later_use_kind(borrow, spans, location);
-                    BorrowExplanation::UsedLater(later_use.0, later_use.1)
-                }
-            }
-
-            Some(Cause::DropVar(local, location)) => {
-                let mut should_note_order = false;
-                if self.local_names[local].is_some() {
-                    if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
-                        if let Some(borrowed_local) = place.as_local() {
-                            if self.local_names[borrowed_local].is_some()
-                                && local != borrowed_local
-                            {
-                                should_note_order = true;
-                            }
-                        }
-                    }
-                }
-
-                BorrowExplanation::UsedLaterWhenDropped {
-                    drop_loc: location,
-                    dropped_local: local,
-                    should_note_order,
-                }
-            }
-
-            None => {
-                if let Some(region) = regioncx.to_error_region_vid(borrow_region_vid) {
-                    let (category, from_closure, span, region_name) =
-                        self.nonlexical_regioncx.free_region_constraint_info(
-                            &self.body,
-                            &self.local_names,
-                            &self.upvars,
-                            self.mir_def_id,
-                            self.infcx,
-                            borrow_region_vid,
-                            region,
-                        );
-                    if let Some(region_name) = region_name {
-                        let opt_place_desc =
-                            self.describe_place(borrow.borrowed_place.as_ref());
-                        BorrowExplanation::MustBeValidFor {
-                            category,
-                            from_closure,
-                            span,
-                            region_name,
-                            opt_place_desc,
-                        }
-                    } else {
-                        debug!("explain_why_borrow_contains_point: \
-                                Could not generate a region name");
-                        BorrowExplanation::Unexplained
-                    }
-                } else {
-                    debug!("explain_why_borrow_contains_point: \
-                            Could not generate an error region vid");
-                    BorrowExplanation::Unexplained
-                }
-            }
-        }
-    }
-
-    /// true if `borrow_location` can reach `use_location` by going through a loop and
-    /// `use_location` is also inside of that loop
-    fn is_use_in_later_iteration_of_loop(
-        &self,
-        borrow_location: Location,
-        use_location: Location,
-    ) -> bool {
-        let back_edge = self.reach_through_backedge(borrow_location, use_location);
-        back_edge.map_or(false, |back_edge| {
-            self.can_reach_head_of_loop(use_location, back_edge)
-        })
-    }
-
-    /// Returns the outmost back edge if `from` location can reach `to` location passing through
-    /// that back edge
-    fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> {
-        let mut visited_locations = FxHashSet::default();
-        let mut pending_locations = VecDeque::new();
-        visited_locations.insert(from);
-        pending_locations.push_back(from);
-        debug!("reach_through_backedge: from={:?} to={:?}", from, to,);
-
-        let mut outmost_back_edge = None;
-        while let Some(location) = pending_locations.pop_front() {
-            debug!(
-                "reach_through_backedge: location={:?} outmost_back_edge={:?}
-                   pending_locations={:?} visited_locations={:?}",
-                location, outmost_back_edge, pending_locations, visited_locations
-            );
-
-            if location == to && outmost_back_edge.is_some() {
-                // We've managed to reach the use location
-                debug!("reach_through_backedge: found!");
-                return outmost_back_edge;
-            }
-
-            let block = &self.body.basic_blocks()[location.block];
-
-            if location.statement_index < block.statements.len() {
-                let successor = location.successor_within_block();
-                if visited_locations.insert(successor) {
-                    pending_locations.push_back(successor);
-                }
-            } else {
-                pending_locations.extend(
-                    block
-                        .terminator()
-                        .successors()
-                        .map(|bb| Location {
-                            statement_index: 0,
-                            block: *bb,
-                        })
-                        .filter(|s| visited_locations.insert(*s))
-                        .map(|s| {
-                            if self.is_back_edge(location, s) {
-                                match outmost_back_edge {
-                                    None => {
-                                        outmost_back_edge = Some(location);
-                                    }
-
-                                    Some(back_edge)
-                                        if location.dominates(back_edge, &self.dominators) =>
-                                    {
-                                        outmost_back_edge = Some(location);
-                                    }
-
-                                    Some(_) => {}
-                                }
-                            }
-
-                            s
-                        }),
-                );
-            }
-        }
-
-        None
-    }
-
-    /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the
-    /// intermediate nodes
-    fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool {
-        self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default())
-    }
-
-    fn find_loop_head_dfs(
-        &self,
-        from: Location,
-        loop_head: Location,
-        visited_locations: &mut FxHashSet<Location>,
-    ) -> bool {
-        visited_locations.insert(from);
-
-        if from == loop_head {
-            return true;
-        }
-
-        if loop_head.dominates(from, &self.dominators) {
-            let block = &self.body.basic_blocks()[from.block];
-
-            if from.statement_index < block.statements.len() {
-                let successor = from.successor_within_block();
-
-                if !visited_locations.contains(&successor)
-                    && self.find_loop_head_dfs(successor, loop_head, visited_locations)
-                {
-                    return true;
-                }
-            } else {
-                for bb in block.terminator().successors() {
-                    let successor = Location {
-                        statement_index: 0,
-                        block: *bb,
-                    };
-
-                    if !visited_locations.contains(&successor)
-                        && self.find_loop_head_dfs(successor, loop_head, visited_locations)
-                    {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        false
-    }
-
-    /// True if an edge `source -> target` is a backedge -- in other words, if the target
-    /// dominates the source.
-    fn is_back_edge(&self, source: Location, target: Location) -> bool {
-        target.dominates(source, &self.dominators)
-    }
-
-    /// Determine how the borrow was later used.
-    fn later_use_kind(
-        &self,
-        borrow: &BorrowData<'tcx>,
-        use_spans: UseSpans,
-        location: Location,
-    ) -> (LaterUseKind, Span) {
-        match use_spans {
-            UseSpans::ClosureUse { var_span, .. } => {
-                // Used in a closure.
-                (LaterUseKind::ClosureCapture, var_span)
-            }
-            UseSpans::OtherUse(span) => {
-                let block = &self.body.basic_blocks()[location.block];
-
-                let kind = if let Some(&Statement {
-                    kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
-                    ..
-                }) = block.statements.get(location.statement_index)
-                {
-                    LaterUseKind::FakeLetRead
-                } else if self.was_captured_by_trait_object(borrow) {
-                    LaterUseKind::TraitCapture
-                } else if location.statement_index == block.statements.len() {
-                    if let TerminatorKind::Call {
-                        ref func,
-                        from_hir_call: true,
-                        ..
-                    } = block.terminator().kind
-                    {
-                        // Just point to the function, to reduce the chance of overlapping spans.
-                        let function_span = match func {
-                            Operand::Constant(c) => c.span,
-                            Operand::Copy(place) |
-                            Operand::Move(place) => {
-                                if let Some(l) = place.as_local() {
-                                    let local_decl = &self.body.local_decls[l];
-                                    if self.local_names[l].is_none() {
-                                        local_decl.source_info.span
-                                    } else {
-                                        span
-                                    }
-                                } else {
-                                    span
-                                }
-                            }
-                        };
-                        return (LaterUseKind::Call, function_span);
-                    } else {
-                        LaterUseKind::Other
-                    }
-                } else {
-                    LaterUseKind::Other
-                };
-
-                (kind, span)
-            }
-        }
-    }
-
-    /// Checks if a borrowed value was captured by a trait object. We do this by
-    /// looking forward in the MIR from the reserve location and checking if we see
-    /// a unsized cast to a trait object on our data.
-    fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
-        // Start at the reserve location, find the place that we want to see cast to a trait object.
-        let location = borrow.reserve_location;
-        let block = &self.body[location.block];
-        let stmt = block.statements.get(location.statement_index);
-        debug!(
-            "was_captured_by_trait_object: location={:?} stmt={:?}",
-            location, stmt
-        );
-
-        // We make a `queue` vector that has the locations we want to visit. As of writing, this
-        // will only ever have one item at any given time, but by using a vector, we can pop from
-        // it which simplifies the termination logic.
-        let mut queue = vec![location];
-        let mut target = if let Some(&Statement {
-            kind: StatementKind::Assign(box(ref place, _)),
-            ..
-        }) = stmt {
-            if let Some(local) = place.as_local() {
-                local
-            } else {
-                return false;
-            }
-        } else {
-            return false;
-        };
-
-        debug!(
-            "was_captured_by_trait: target={:?} queue={:?}",
-            target, queue
-        );
-        while let Some(current_location) = queue.pop() {
-            debug!("was_captured_by_trait: target={:?}", target);
-            let block = &self.body[current_location.block];
-            // We need to check the current location to find out if it is a terminator.
-            let is_terminator = current_location.statement_index == block.statements.len();
-            if !is_terminator {
-                let stmt = &block.statements[current_location.statement_index];
-                debug!("was_captured_by_trait_object: stmt={:?}", stmt);
-
-                // The only kind of statement that we care about is assignments...
-                if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
-                    let into = match place.local_or_deref_local() {
-                        Some(into) => into,
-                        None => {
-                            // Continue at the next location.
-                            queue.push(current_location.successor_within_block());
-                            continue;
-                        }
-                    };
-
-                    match rvalue {
-                        // If we see a use, we should check whether it is our data, and if so
-                        // update the place that we're looking for to that new place.
-                        Rvalue::Use(operand) => match operand {
-                            Operand::Copy(place)
-                            | Operand::Move(place) => {
-                                if let Some(from) = place.as_local() {
-                                    if from == target {
-                                        target = into;
-                                    }
-                                }
-                            }
-                            _ => {}
-                        },
-                        // If we see a unsized cast, then if it is our data we should check
-                        // whether it is being cast to a trait object.
-                        Rvalue::Cast(
-                            CastKind::Pointer(PointerCast::Unsize), operand, ty
-                        ) => match operand {
-                            Operand::Copy(place)
-                            | Operand::Move(place) => {
-                                if let Some(from) = place.as_local() {
-                                    if from == target {
-                                        debug!("was_captured_by_trait_object: ty={:?}", ty);
-                                        // Check the type for a trait object.
-                                        return match ty.kind {
-                                            // `&dyn Trait`
-                                            ty::Ref(_, ty, _) if ty.is_trait() => true,
-                                            // `Box<dyn Trait>`
-                                            _ if ty.is_box() && ty.boxed_ty().is_trait() => true,
-                                            // `dyn Trait`
-                                            _ if ty.is_trait() => true,
-                                            // Anything else.
-                                            _ => false,
-                                        };
-                                    }
-                                }
-                                return false;
-                            }
-                            _ => return false,
-                        },
-                        _ => {}
-                    }
-                }
-
-                // Continue at the next location.
-                queue.push(current_location.successor_within_block());
-            } else {
-                // The only thing we need to do for terminators is progress to the next block.
-                let terminator = block.terminator();
-                debug!("was_captured_by_trait_object: terminator={:?}", terminator);
-
-                if let TerminatorKind::Call {
-                    destination: Some((place, block)),
-                    args,
-                    ..
-                } = &terminator.kind {
-                    if let Some(dest) = place.as_local() {
-                        debug!(
-                            "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
-                            target, dest, args
-                        );
-                        // Check if one of the arguments to this function is the target place.
-                        let found_target = args.iter().any(|arg| {
-                            if let Operand::Move(place) = arg {
-                                if let Some(potential) = place.as_local() {
-                                    potential == target
-                                } else {
-                                    false
-                                }
-                            } else {
-                                false
-                            }
-                        });
-
-                        // If it is, follow this to the next block and update the target.
-                        if found_target {
-                            target = dest;
-                            queue.push(block.start_location());
-                        }
-                    }
-                }
-            }
-
-            debug!("was_captured_by_trait: queue={:?}", queue);
-        }
-
-        // We didn't find anything and ran out of locations to check.
-        false
-    }
-}
index 16182fe24fa4f171f2487da2502800bea44d39ad..b9363200cdf2855dc60ab6c6801895642f8d7ecd 100644 (file)
 use crate::util::pretty;
 
 mod constraint_generation;
-pub mod explain_borrow;
 mod facts;
 mod invalidation;
-crate mod region_infer;
 mod renumber;
-crate mod type_check;
-mod universal_regions;
 
-mod constraints;
 mod member_constraints;
 
+crate mod constraints;
+crate mod universal_regions;
+crate mod type_check;
+crate mod region_infer;
+
 use self::facts::AllFacts;
 use self::region_infer::RegionInferenceContext;
 use self::universal_regions::UniversalRegions;
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
deleted file mode 100644 (file)
index 5e79a2f..0000000
+++ /dev/null
@@ -1,937 +0,0 @@
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::type_check::Locations;
-use crate::borrow_check::nll::universal_regions::DefiningTy;
-use crate::borrow_check::nll::ConstraintDescription;
-use crate::borrow_check::Upvar;
-use crate::util::borrowck_errors;
-use rustc::hir::def_id::DefId;
-use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc::infer::InferCtxt;
-use rustc::infer::NLLRegionVariableOrigin;
-use rustc::mir::{ConstraintCategory, Local, Location, Body};
-use rustc::ty::{self, RegionVid};
-use rustc_index::vec::IndexVec;
-use rustc_errors::DiagnosticBuilder;
-use std::collections::VecDeque;
-use syntax::errors::Applicability;
-use syntax::symbol::kw;
-use syntax_pos::Span;
-use syntax_pos::symbol::Symbol;
-
-use self::outlives_suggestion::OutlivesSuggestionBuilder;
-
-pub mod outlives_suggestion;
-
-mod region_name;
-mod var_name;
-
-crate use self::region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
-
-impl ConstraintDescription for ConstraintCategory {
-    fn description(&self) -> &'static str {
-        // Must end with a space. Allows for empty names to be provided.
-        match self {
-            ConstraintCategory::Assignment => "assignment ",
-            ConstraintCategory::Return => "returning this value ",
-            ConstraintCategory::Yield => "yielding this value ",
-            ConstraintCategory::UseAsConst => "using this value as a constant ",
-            ConstraintCategory::UseAsStatic => "using this value as a static ",
-            ConstraintCategory::Cast => "cast ",
-            ConstraintCategory::CallArgument => "argument ",
-            ConstraintCategory::TypeAnnotation => "type annotation ",
-            ConstraintCategory::ClosureBounds => "closure body ",
-            ConstraintCategory::SizedBound => "proving this value is `Sized` ",
-            ConstraintCategory::CopyBound => "copying this value ",
-            ConstraintCategory::OpaqueType => "opaque type ",
-            ConstraintCategory::Boring
-            | ConstraintCategory::BoringNoLocation
-            | ConstraintCategory::Internal => "",
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-enum Trace {
-    StartRegion,
-    FromOutlivesConstraint(OutlivesConstraint),
-    NotVisited,
-}
-
-/// Various pieces of state used when reporting borrow checker errors.
-pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
-    /// The region inference context used for borrow chekcing this MIR body.
-    region_infcx: &'b RegionInferenceContext<'tcx>,
-
-    /// The inference context used for type checking.
-    infcx: &'b InferCtxt<'a, 'tcx>,
-
-    /// The MIR def we are reporting errors on.
-    mir_def_id: DefId,
-
-    /// The MIR body we are reporting errors on (for convenience).
-    body: &'b Body<'tcx>,
-
-    /// User variable names for MIR locals (where applicable).
-    local_names: &'b IndexVec<Local, Option<Symbol>>,
-
-    /// Any upvars for the MIR body we have kept track of during borrow checking.
-    upvars: &'b [Upvar],
-}
-
-/// Information about the various region constraints involved in a borrow checker error.
-#[derive(Clone, Debug)]
-pub struct ErrorConstraintInfo {
-    // fr: outlived_fr
-    fr: RegionVid,
-    fr_is_local: bool,
-    outlived_fr: RegionVid,
-    outlived_fr_is_local: bool,
-
-    // Category and span for best blame constraint
-    category: ConstraintCategory,
-    span: Span,
-}
-
-impl<'tcx> RegionInferenceContext<'tcx> {
-    /// Tries to find the best constraint to blame for the fact that
-    /// `R: from_region`, where `R` is some region that meets
-    /// `target_test`. This works by following the constraint graph,
-    /// creating a constraint path that forces `R` to outlive
-    /// `from_region`, and then finding the best choices within that
-    /// path to blame.
-    fn best_blame_constraint(
-        &self,
-        body: &Body<'tcx>,
-        from_region: RegionVid,
-        from_region_origin: NLLRegionVariableOrigin,
-        target_test: impl Fn(RegionVid) -> bool,
-    ) -> (ConstraintCategory, bool, Span) {
-        debug!("best_blame_constraint(from_region={:?}, from_region_origin={:?})",
-            from_region, from_region_origin);
-
-        // Find all paths
-        let (path, target_region) =
-            self.find_constraint_paths_between_regions(from_region, target_test)
-                .unwrap();
-        debug!(
-            "best_blame_constraint: path={:#?}",
-            path.iter()
-                .map(|&c| format!(
-                    "{:?} ({:?}: {:?})",
-                    c,
-                    self.constraint_sccs.scc(c.sup),
-                    self.constraint_sccs.scc(c.sub),
-                ))
-                .collect::<Vec<_>>()
-        );
-
-        // Classify each of the constraints along the path.
-        let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path.iter()
-            .map(|constraint| {
-                if constraint.category == ConstraintCategory::ClosureBounds {
-                    self.retrieve_closure_constraint_info(body, &constraint)
-                } else {
-                    (constraint.category, false, constraint.locations.span(body))
-                }
-            })
-            .collect();
-        debug!(
-            "best_blame_constraint: categorized_path={:#?}",
-            categorized_path
-        );
-
-        // To find the best span to cite, we first try to look for the
-        // final constraint that is interesting and where the `sup` is
-        // not unified with the ultimate target region. The reason
-        // for this is that we have a chain of constraints that lead
-        // from the source to the target region, something like:
-        //
-        //    '0: '1 ('0 is the source)
-        //    '1: '2
-        //    '2: '3
-        //    '3: '4
-        //    '4: '5
-        //    '5: '6 ('6 is the target)
-        //
-        // Some of those regions are unified with `'6` (in the same
-        // SCC).  We want to screen those out. After that point, the
-        // "closest" constraint we have to the end is going to be the
-        // most likely to be the point where the value escapes -- but
-        // we still want to screen for an "interesting" point to
-        // highlight (e.g., a call site or something).
-        let target_scc = self.constraint_sccs.scc(target_region);
-        let mut range = 0..path.len();
-
-        // As noted above, when reporting an error, there is typically a chain of constraints
-        // leading from some "source" region which must outlive some "target" region.
-        // In most cases, we prefer to "blame" the constraints closer to the target --
-        // but there is one exception. When constraints arise from higher-ranked subtyping,
-        // we generally prefer to blame the source value,
-        // as the "target" in this case tends to be some type annotation that the user gave.
-        // Therefore, if we find that the region origin is some instantiation
-        // of a higher-ranked region, we start our search from the "source" point
-        // rather than the "target", and we also tweak a few other things.
-        //
-        // An example might be this bit of Rust code:
-        //
-        // ```rust
-        // let x: fn(&'static ()) = |_| {};
-        // let y: for<'a> fn(&'a ()) = x;
-        // ```
-        //
-        // In MIR, this will be converted into a combination of assignments and type ascriptions.
-        // In particular, the 'static is imposed through a type ascription:
-        //
-        // ```rust
-        // x = ...;
-        // AscribeUserType(x, fn(&'static ())
-        // y = x;
-        // ```
-        //
-        // We wind up ultimately with constraints like
-        //
-        // ```rust
-        // !a: 'temp1 // from the `y = x` statement
-        // 'temp1: 'temp2
-        // 'temp2: 'static // from the AscribeUserType
-        // ```
-        //
-        // and here we prefer to blame the source (the y = x statement).
-        let blame_source = match from_region_origin {
-            NLLRegionVariableOrigin::FreeRegion
-                | NLLRegionVariableOrigin::Existential { from_forall: false  } => {
-                    true
-            }
-            NLLRegionVariableOrigin::Placeholder(_)
-                | NLLRegionVariableOrigin::Existential { from_forall: true  } => {
-                    false
-            }
-        };
-
-        let find_region = |i: &usize| {
-            let constraint = path[*i];
-
-            let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
-
-            if blame_source {
-                match categorized_path[*i].0 {
-                    ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
-                    ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
-                    ConstraintCategory::TypeAnnotation | ConstraintCategory::Return |
-                    ConstraintCategory::Yield => true,
-                    _ => constraint_sup_scc != target_scc,
-                }
-            } else {
-                match categorized_path[*i].0 {
-                    ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
-                    ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
-                    _ => true
-                }
-            }
-        };
-
-        let best_choice = if blame_source {
-            range.rev().find(find_region)
-        } else {
-            range.find(find_region)
-        };
-
-        debug!("best_blame_constraint: best_choice={:?} blame_source={}",
-            best_choice, blame_source);
-
-        if let Some(i) = best_choice {
-            if let Some(next) = categorized_path.get(i + 1) {
-                if categorized_path[i].0 == ConstraintCategory::Return
-                    && next.0 == ConstraintCategory::OpaqueType
-                {
-                    // The return expression is being influenced by the return type being
-                    // impl Trait, point at the return type and not the return expr.
-                    return *next;
-                }
-            }
-            return categorized_path[i];
-        }
-
-        // If that search fails, that is.. unusual. Maybe everything
-        // is in the same SCC or something. In that case, find what
-        // appears to be the most interesting point to report to the
-        // user via an even more ad-hoc guess.
-        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
-        debug!("`: sorted_path={:#?}", categorized_path);
-
-        *categorized_path.first().unwrap()
-    }
-
-    /// Walks the graph of constraints (where `'a: 'b` is considered
-    /// an edge `'a -> 'b`) to find all paths from `from_region` to
-    /// `to_region`. The paths are accumulated into the vector
-    /// `results`. The paths are stored as a series of
-    /// `ConstraintIndex` values -- in other words, a list of *edges*.
-    ///
-    /// Returns: a series of constraints as well as the region `R`
-    /// that passed the target test.
-    fn find_constraint_paths_between_regions(
-        &self,
-        from_region: RegionVid,
-        target_test: impl Fn(RegionVid) -> bool,
-    ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> {
-        let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
-        context[from_region] = Trace::StartRegion;
-
-        // Use a deque so that we do a breadth-first search. We will
-        // stop at the first match, which ought to be the shortest
-        // path (fewest constraints).
-        let mut deque = VecDeque::new();
-        deque.push_back(from_region);
-
-        while let Some(r) = deque.pop_front() {
-            debug!(
-                "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}",
-                from_region,
-                r,
-                self.region_value_str(r),
-            );
-
-            // Check if we reached the region we were looking for. If so,
-            // we can reconstruct the path that led to it and return it.
-            if target_test(r) {
-                let mut result = vec![];
-                let mut p = r;
-                loop {
-                    match context[p] {
-                        Trace::NotVisited => {
-                            bug!("found unvisited region {:?} on path to {:?}", p, r)
-                        }
-
-                        Trace::FromOutlivesConstraint(c) => {
-                            result.push(c);
-                            p = c.sup;
-                        }
-
-                        Trace::StartRegion => {
-                            result.reverse();
-                            return Some((result, r));
-                        }
-                    }
-                }
-            }
-
-            // Otherwise, walk over the outgoing constraints and
-            // enqueue any regions we find, keeping track of how we
-            // reached them.
-
-            // A constraint like `'r: 'x` can come from our constraint
-            // graph.
-            let fr_static = self.universal_regions.fr_static;
-            let outgoing_edges_from_graph = self.constraint_graph
-                .outgoing_edges(r, &self.constraints, fr_static);
-
-            // Always inline this closure because it can be hot.
-            let mut handle_constraint = #[inline(always)] |constraint: OutlivesConstraint| {
-                debug_assert_eq!(constraint.sup, r);
-                let sub_region = constraint.sub;
-                if let Trace::NotVisited = context[sub_region] {
-                    context[sub_region] = Trace::FromOutlivesConstraint(constraint);
-                    deque.push_back(sub_region);
-                }
-            };
-
-            // This loop can be hot.
-            for constraint in outgoing_edges_from_graph {
-                handle_constraint(constraint);
-            }
-
-            // Member constraints can also give rise to `'r: 'x` edges that
-            // were not part of the graph initially, so watch out for those.
-            // (But they are extremely rare; this loop is very cold.)
-            for constraint in self.applied_member_constraints(r) {
-                let p_c = &self.member_constraints[constraint.member_constraint_index];
-                let constraint = OutlivesConstraint {
-                    sup: r,
-                    sub: constraint.min_choice,
-                    locations: Locations::All(p_c.definition_span),
-                    category: ConstraintCategory::OpaqueType,
-                };
-                handle_constraint(constraint);
-            }
-        }
-
-        None
-    }
-
-    /// Report an error because the universal region `fr` was required to outlive
-    /// `outlived_fr` but it is not known to do so. For example:
-    ///
-    /// ```
-    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
-    /// ```
-    ///
-    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
-    pub(super) fn report_error<'a>(
-        &'a self,
-        body: &Body<'tcx>,
-        local_names: &IndexVec<Local, Option<Symbol>>,
-        upvars: &[Upvar],
-        infcx: &'a InferCtxt<'a, 'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        fr_origin: NLLRegionVariableOrigin,
-        outlived_fr: RegionVid,
-        outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> DiagnosticBuilder<'a> {
-        debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
-
-        let (category, _, span) = self.best_blame_constraint(body, fr, fr_origin, |r| {
-            self.provides_universal_region(r, fr, outlived_fr)
-        });
-
-        debug!("report_error: category={:?} {:?}", category, span);
-        // Check if we can use one of the "nice region errors".
-        if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
-            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
-            let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
-            if let Some(diag) = nice.try_report_from_nll() {
-                return diag;
-            }
-        }
-
-        let (fr_is_local, outlived_fr_is_local): (bool, bool) = (
-            self.universal_regions.is_local_free_region(fr),
-            self.universal_regions.is_local_free_region(outlived_fr),
-        );
-
-        debug!(
-            "report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
-            fr_is_local, outlived_fr_is_local, category
-        );
-
-        let errctx = ErrorReportingCtx {
-            region_infcx: self,
-            infcx,
-            mir_def_id,
-            body,
-            local_names,
-            upvars,
-        };
-
-        let errci = ErrorConstraintInfo {
-            fr, outlived_fr, fr_is_local, outlived_fr_is_local, category, span
-        };
-
-        match (category, fr_is_local, outlived_fr_is_local) {
-            (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => {
-                self.report_fnmut_error(&errctx, &errci, renctx)
-            }
-            (ConstraintCategory::Assignment, true, false)
-            | (ConstraintCategory::CallArgument, true, false) => {
-                let mut db = self.report_escaping_data_error(&errctx, &errci, renctx);
-
-                outlives_suggestion.intermediate_suggestion(&errctx, &errci, renctx, &mut db);
-                outlives_suggestion.collect_constraint(fr, outlived_fr);
-
-                db
-            }
-            _ => {
-                let mut db = self.report_general_error(&errctx, &errci, renctx);
-
-                outlives_suggestion.intermediate_suggestion(&errctx, &errci, renctx, &mut db);
-                outlives_suggestion.collect_constraint(fr, outlived_fr);
-
-                db
-            }
-        }
-    }
-
-    /// We have a constraint `fr1: fr2` that is not satisfied, where
-    /// `fr2` represents some universal region. Here, `r` is some
-    /// region where we know that `fr1: r` and this function has the
-    /// job of determining whether `r` is "to blame" for the fact that
-    /// `fr1: fr2` is required.
-    ///
-    /// This is true under two conditions:
-    ///
-    /// - `r == fr2`
-    /// - `fr2` is `'static` and `r` is some placeholder in a universe
-    ///   that cannot be named by `fr1`; in that case, we will require
-    ///   that `fr1: 'static` because it is the only way to `fr1: r` to
-    ///   be satisfied. (See `add_incompatible_universe`.)
-    fn provides_universal_region(&self, r: RegionVid, fr1: RegionVid, fr2: RegionVid) -> bool {
-        debug!(
-            "provides_universal_region(r={:?}, fr1={:?}, fr2={:?})",
-            r, fr1, fr2
-        );
-        let result = {
-            r == fr2 || {
-                fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r)
-            }
-        };
-        debug!("provides_universal_region: result = {:?}", result);
-        result
-    }
-
-    /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
-    /// This function expects `fr` to be local and `outlived_fr` to not be local.
-    ///
-    /// ```text
-    /// error: captured variable cannot escape `FnMut` closure body
-    ///   --> $DIR/issue-53040.rs:15:8
-    ///    |
-    /// LL |     || &mut v;
-    ///    |     -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
-    ///    |     |
-    ///    |     inferred to be a `FnMut` closure
-    ///    |
-    ///    = note: `FnMut` closures only have access to their captured variables while they are
-    ///            executing...
-    ///    = note: ...therefore, returned references to captured variables will escape the closure
-    /// ```
-    fn report_fnmut_error(
-        &self,
-        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
-        errci: &ErrorConstraintInfo,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> DiagnosticBuilder<'_> {
-        let ErrorConstraintInfo {
-            outlived_fr, span, ..
-        } = errci;
-
-        let mut diag = errctx
-            .infcx
-            .tcx
-            .sess
-            .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
-
-        // We should check if the return type of this closure is in fact a closure - in that
-        // case, we can special case the error further.
-        let return_type_is_closure = self.universal_regions.unnormalized_output_ty.is_closure();
-        let message = if return_type_is_closure {
-            "returns a closure that contains a reference to a captured variable, which then \
-             escapes the closure body"
-        } else {
-            "returns a reference to a captured variable which escapes the closure body"
-        };
-
-        diag.span_label(*span, message);
-
-        match self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap().source {
-            RegionNameSource::NamedEarlyBoundRegion(fr_span)
-            | RegionNameSource::NamedFreeRegion(fr_span)
-            | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
-            | RegionNameSource::CannotMatchHirTy(fr_span, _)
-            | RegionNameSource::MatchedHirTy(fr_span)
-            | RegionNameSource::MatchedAdtAndSegment(fr_span)
-            | RegionNameSource::AnonRegionFromUpvar(fr_span, _)
-            | RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
-                diag.span_label(fr_span, "inferred to be a `FnMut` closure");
-            }
-            _ => {}
-        }
-
-        diag.note(
-            "`FnMut` closures only have access to their captured variables while they are \
-             executing...",
-        );
-        diag.note("...therefore, they cannot allow references to captured variables to escape");
-
-        diag
-    }
-
-    /// Reports a error specifically for when data is escaping a closure.
-    ///
-    /// ```text
-    /// error: borrowed data escapes outside of function
-    ///   --> $DIR/lifetime-bound-will-change-warning.rs:44:5
-    ///    |
-    /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
-    ///    |              - `x` is a reference that is only valid in the function body
-    /// LL |     // but ref_obj will not, so warn.
-    /// LL |     ref_obj(x)
-    ///    |     ^^^^^^^^^^ `x` escapes the function body here
-    /// ```
-    fn report_escaping_data_error(
-        &self,
-        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
-        errci: &ErrorConstraintInfo,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> DiagnosticBuilder<'_> {
-        let ErrorReportingCtx {
-            infcx, body, upvars, local_names, ..
-        } = errctx;
-
-        let ErrorConstraintInfo {
-            span, category, ..
-        } = errci;
-
-        let fr_name_and_span =
-            self.get_var_name_and_span_for_region(infcx.tcx, body, local_names, upvars, errci.fr);
-        let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
-            infcx.tcx,
-            body,
-            local_names,
-            upvars,
-            errci.outlived_fr,
-        );
-
-        let escapes_from = match self.universal_regions.defining_ty {
-            DefiningTy::Closure(..) => "closure",
-            DefiningTy::Generator(..) => "generator",
-            DefiningTy::FnDef(..) => "function",
-            DefiningTy::Const(..) => "const",
-        };
-
-        // Revert to the normal error in these cases.
-        // Assignments aren't "escapes" in function items.
-        if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
-            || (*category == ConstraintCategory::Assignment && escapes_from == "function")
-            || escapes_from == "const"
-        {
-            return self.report_general_error(
-                errctx,
-                &ErrorConstraintInfo {
-                    fr_is_local: true,
-                    outlived_fr_is_local: false,
-                    .. *errci
-                },
-                renctx,
-            );
-        }
-
-        let mut diag = borrowck_errors::borrowed_data_escapes_closure(
-            infcx.tcx,
-            *span,
-            escapes_from,
-        );
-
-        if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
-            diag.span_label(
-                outlived_fr_span,
-                format!(
-                    "`{}` is declared here, outside of the {} body",
-                    outlived_fr_name, escapes_from
-                ),
-            );
-        }
-
-        if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
-            diag.span_label(
-                fr_span,
-                format!(
-                    "`{}` is a reference that is only valid in the {} body",
-                    fr_name, escapes_from
-                ),
-            );
-
-            diag.span_label(
-                *span,
-                format!("`{}` escapes the {} body here", fr_name, escapes_from),
-            );
-        }
-
-        diag
-    }
-
-    /// Reports a region inference error for the general case with named/synthesized lifetimes to
-    /// explain what is happening.
-    ///
-    /// ```text
-    /// error: unsatisfied lifetime constraints
-    ///   --> $DIR/regions-creating-enums3.rs:17:5
-    ///    |
-    /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
-    ///    |                -- -- lifetime `'b` defined here
-    ///    |                |
-    ///    |                lifetime `'a` defined here
-    /// LL |     ast::add(x, y)
-    ///    |     ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
-    ///    |                    is returning data with lifetime `'b`
-    /// ```
-    fn report_general_error(
-        &self,
-        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
-        errci: &ErrorConstraintInfo,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> DiagnosticBuilder<'_> {
-        let ErrorReportingCtx {
-            infcx, mir_def_id, ..
-        } = errctx;
-        let ErrorConstraintInfo {
-            fr, fr_is_local, outlived_fr, outlived_fr_is_local, span, category, ..
-        } = errci;
-
-        let mut diag = infcx.tcx.sess.struct_span_err(
-            *span,
-            "lifetime may not live long enough"
-        );
-
-        let mir_def_name = if infcx.tcx.is_closure(*mir_def_id) {
-            "closure"
-        } else {
-            "function"
-        };
-
-        let fr_name = self.give_region_a_name(errctx, renctx, *fr).unwrap();
-        fr_name.highlight_region_name(&mut diag);
-        let outlived_fr_name = self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap();
-        outlived_fr_name.highlight_region_name(&mut diag);
-
-        match (category, outlived_fr_is_local, fr_is_local) {
-            (ConstraintCategory::Return, true, _) => {
-                diag.span_label(
-                    *span,
-                    format!(
-                        "{} was supposed to return data with lifetime `{}` but it is returning \
-                         data with lifetime `{}`",
-                        mir_def_name, outlived_fr_name, fr_name
-                    ),
-                );
-            }
-            _ => {
-                diag.span_label(
-                    *span,
-                    format!(
-                        "{}requires that `{}` must outlive `{}`",
-                        category.description(),
-                        fr_name,
-                        outlived_fr_name,
-                    ),
-                );
-            }
-        }
-
-        self.add_static_impl_trait_suggestion(infcx, &mut diag, *fr, fr_name, *outlived_fr);
-
-        diag
-    }
-
-    /// Adds a suggestion to errors where a `impl Trait` is returned.
-    ///
-    /// ```text
-    /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
-    ///       a constraint
-    ///    |
-    /// LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
-    ///    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    /// ```
-    fn add_static_impl_trait_suggestion(
-        &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        diag: &mut DiagnosticBuilder<'_>,
-        fr: RegionVid,
-        // We need to pass `fr_name` - computing it again will label it twice.
-        fr_name: RegionName,
-        outlived_fr: RegionVid,
-    ) {
-        if let (Some(f), Some(ty::RegionKind::ReStatic)) =
-            (self.to_error_region(fr), self.to_error_region(outlived_fr))
-        {
-            if let Some((ty::TyS {
-                kind: ty::Opaque(did, substs),
-                ..
-            }, _)) = infcx
-                .tcx
-                .is_suitable_region(f)
-                .map(|r| r.def_id)
-                .map(|id| infcx.tcx.return_type_impl_trait(id))
-                .unwrap_or(None)
-            {
-                // Check whether or not the impl trait return type is intended to capture
-                // data with the static lifetime.
-                //
-                // eg. check for `impl Trait + 'static` instead of `impl Trait`.
-                let has_static_predicate = {
-                    let predicates_of = infcx.tcx.predicates_of(*did);
-                    let bounds = predicates_of.instantiate(infcx.tcx, substs);
-
-                    let mut found = false;
-                    for predicate in bounds.predicates {
-                        if let ty::Predicate::TypeOutlives(binder) = predicate {
-                            if let ty::OutlivesPredicate(_, ty::RegionKind::ReStatic) =
-                                binder.skip_binder()
-                            {
-                                found = true;
-                                break;
-                            }
-                        }
-                    }
-
-                    found
-                };
-
-                debug!(
-                    "add_static_impl_trait_suggestion: has_static_predicate={:?}",
-                    has_static_predicate
-                );
-                let static_str = kw::StaticLifetime;
-                // If there is a static predicate, then the only sensible suggestion is to replace
-                // fr with `'static`.
-                if has_static_predicate {
-                    diag.help(&format!(
-                        "consider replacing `{}` with `{}`",
-                        fr_name, static_str,
-                    ));
-                } else {
-                    // Otherwise, we should suggest adding a constraint on the return type.
-                    let span = infcx.tcx.def_span(*did);
-                    if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
-                        let suggestable_fr_name = if fr_name.was_named() {
-                            fr_name.to_string()
-                        } else {
-                            "'_".to_string()
-                        };
-
-                        diag.span_suggestion(
-                            span,
-                            &format!(
-                                "to allow this `impl Trait` to capture borrowed data with lifetime \
-                                 `{}`, add `{}` as a constraint",
-                                fr_name, suggestable_fr_name,
-                            ),
-                            format!("{} + {}", snippet, suggestable_fr_name),
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    crate fn free_region_constraint_info(
-        &self,
-        body: &Body<'tcx>,
-        local_names: &IndexVec<Local, Option<Symbol>>,
-        upvars: &[Upvar],
-        mir_def_id: DefId,
-        infcx: &InferCtxt<'_, 'tcx>,
-        borrow_region: RegionVid,
-        outlived_region: RegionVid,
-    ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
-        let (category, from_closure, span) = self.best_blame_constraint(
-            body,
-            borrow_region,
-            NLLRegionVariableOrigin::FreeRegion,
-            |r| self.provides_universal_region(r, borrow_region, outlived_region)
-        );
-
-        let mut renctx = RegionErrorNamingCtx::new();
-        let errctx = ErrorReportingCtx {
-            infcx, body, local_names, upvars, mir_def_id,
-            region_infcx: self,
-        };
-        let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
-
-        (category, from_closure, span, outlived_fr_name)
-    }
-
-    // Finds some region R such that `fr1: R` and `R` is live at
-    // `elem`.
-    crate fn find_sub_region_live_at(
-        &self,
-        fr1: RegionVid,
-        elem: Location,
-    ) -> RegionVid {
-        debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem);
-        self.find_constraint_paths_between_regions(fr1, |r| {
-            // First look for some `r` such that `fr1: r` and `r` is live at `elem`
-            debug!(
-                "find_sub_region_live_at: liveness_constraints for {:?} are {:?}",
-                r,
-                self.liveness_constraints.region_value_str(r),
-            );
-            self.liveness_constraints.contains(r, elem)
-        }).or_else(|| {
-                // If we fail to find that, we may find some `r` such that
-                // `fr1: r` and `r` is a placeholder from some universe
-                // `fr1` cannot name. This would force `fr1` to be
-                // `'static`.
-                self.find_constraint_paths_between_regions(fr1, |r| {
-                    self.cannot_name_placeholder(fr1, r)
-                })
-            })
-            .or_else(|| {
-                // If we fail to find THAT, it may be that `fr1` is a
-                // placeholder that cannot "fit" into its SCC. In that
-                // case, there should be some `r` where `fr1: r`, both
-                // `fr1` and `r` are in the same SCC, and `fr1` is a
-                // placeholder that `r` cannot name. We can blame that
-                // edge.
-                self.find_constraint_paths_between_regions(fr1, |r| {
-                    self.constraint_sccs.scc(fr1) == self.constraint_sccs.scc(r)
-                        && self.cannot_name_placeholder(r, fr1)
-                })
-            })
-            .map(|(_path, r)| r)
-            .unwrap()
-    }
-
-    // Finds a good span to blame for the fact that `fr1` outlives `fr2`.
-    crate fn find_outlives_blame_span(
-        &self,
-        body: &Body<'tcx>,
-        fr1: RegionVid,
-        fr1_origin: NLLRegionVariableOrigin,
-        fr2: RegionVid,
-    ) -> (ConstraintCategory, Span) {
-        let (category, _, span) = self.best_blame_constraint(
-            body,
-            fr1,
-            fr1_origin,
-            |r| self.provides_universal_region(r, fr1, fr2),
-        );
-        (category, span)
-    }
-
-    fn retrieve_closure_constraint_info(
-        &self,
-        body: &Body<'tcx>,
-        constraint: &OutlivesConstraint,
-    ) -> (ConstraintCategory, bool, Span) {
-        let loc = match constraint.locations {
-            Locations::All(span) => return (constraint.category, false, span),
-            Locations::Single(loc) => loc,
-        };
-
-        let opt_span_category =
-            self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
-        opt_span_category
-            .map(|&(category, span)| (category, true, span))
-            .unwrap_or((constraint.category, false, body.source_info(loc).span))
-    }
-
-    /// Returns `true` if a closure is inferred to be an `FnMut` closure.
-    crate fn is_closure_fn_mut(&self, infcx: &InferCtxt<'_, 'tcx>, fr: RegionVid) -> bool {
-        if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
-            if let ty::BoundRegion::BrEnv = free_region.bound_region {
-                if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty {
-                    let closure_kind_ty = substs.as_closure().kind_ty(def_id, infcx.tcx);
-                    return Some(ty::ClosureKind::FnMut) == closure_kind_ty.to_opt_closure_kind();
-                }
-            }
-        }
-
-        false
-    }
-
-    /// If `r2` represents a placeholder region, then this returns
-    /// `true` if `r1` cannot name that placeholder in its
-    /// value; otherwise, returns `false`.
-    fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
-        debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
-
-        match self.definitions[r2].origin {
-            NLLRegionVariableOrigin::Placeholder(placeholder) => {
-                let universe1 = self.definitions[r1].universe;
-                debug!(
-                    "cannot_name_value_of: universe1={:?} placeholder={:?}",
-                    universe1, placeholder
-                );
-                universe1.cannot_name(placeholder.universe)
-            }
-
-            NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential { .. } => {
-                false
-            }
-        }
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs
deleted file mode 100644 (file)
index 938059c..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-//! Contains utilities for generating suggestions for borrowck errors related to unsatisified
-//! outlives constraints.
-
-use std::collections::BTreeMap;
-
-use log::debug;
-use rustc::{hir::def_id::DefId, infer::InferCtxt, ty::RegionVid};
-use rustc::mir::{Body, Local};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Diagnostic, DiagnosticBuilder};
-use rustc_index::vec::IndexVec;
-use syntax_pos::symbol::Symbol;
-
-use smallvec::SmallVec;
-
-use crate::borrow_check::nll::region_infer::{
-    error_reporting::{
-        region_name::{RegionName, RegionNameSource},
-        ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx,
-    },
-    RegionInferenceContext,
-};
-
-/// The different things we could suggest.
-enum SuggestedConstraint {
-    /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ...
-    Outlives(RegionName, SmallVec<[RegionName; 2]>),
-
-    /// 'a = 'b
-    Equal(RegionName, RegionName),
-
-    /// 'a: 'static i.e. 'a = 'static and the user should just use 'static
-    Static(RegionName),
-}
-
-/// Collects information about outlives constraints that needed to be added for a given MIR node
-/// corresponding to a function definition.
-///
-/// Adds a help note suggesting adding a where clause with the needed constraints.
-pub struct OutlivesSuggestionBuilder<'a> {
-    /// The MIR DefId of the fn with the lifetime error.
-    mir_def_id: DefId,
-
-    local_names: &'a IndexVec<Local, Option<Symbol>>,
-
-    /// The list of outlives constraints that need to be added. Specifically, we map each free
-    /// region to all other regions that it must outlive. I will use the shorthand `fr:
-    /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be
-    /// implicit free regions that we inferred. These will need to be given names in the final
-    /// suggestion message.
-    constraints_to_add: BTreeMap<RegionVid, Vec<RegionVid>>,
-}
-
-impl OutlivesSuggestionBuilder<'a> {
-    /// Create a new builder for the given MIR node representing a fn definition.
-    crate fn new(
-        mir_def_id: DefId,
-        local_names: &'a IndexVec<Local, Option<Symbol>>,
-    ) -> Self {
-        OutlivesSuggestionBuilder {
-            mir_def_id,
-            local_names,
-            constraints_to_add: BTreeMap::default(),
-        }
-    }
-
-    /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives
-    /// suggestion.
-    //
-    // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound
-    // region or a named region, avoiding using regions with synthetic names altogether. This
-    // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args).
-    // We can probably be less conservative, since some inferred free regions are namable (e.g.
-    // the user can explicitly name them. To do this, we would allow some regions whose names
-    // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as
-    // naming the `'self` lifetime in methods, etc.
-    fn region_name_is_suggestable(name: &RegionName) -> bool {
-        match name.source {
-            RegionNameSource::NamedEarlyBoundRegion(..)
-            | RegionNameSource::NamedFreeRegion(..)
-            | RegionNameSource::Static => true,
-
-            // Don't give suggestions for upvars, closure return types, or other unnamable
-            // regions.
-            RegionNameSource::SynthesizedFreeEnvRegion(..)
-            | RegionNameSource::CannotMatchHirTy(..)
-            | RegionNameSource::MatchedHirTy(..)
-            | RegionNameSource::MatchedAdtAndSegment(..)
-            | RegionNameSource::AnonRegionFromUpvar(..)
-            | RegionNameSource::AnonRegionFromOutput(..)
-            | RegionNameSource::AnonRegionFromYieldTy(..)
-            | RegionNameSource::AnonRegionFromAsyncFn(..) => {
-                debug!("Region {:?} is NOT suggestable", name);
-                false
-            }
-        }
-    }
-
-    /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`.
-    fn region_vid_to_name(
-        &self,
-        errctx: &ErrorReportingCtx<'_, '_, '_>,
-        renctx: &mut RegionErrorNamingCtx,
-        region: RegionVid,
-    ) -> Option<RegionName> {
-        errctx
-            .region_infcx
-            .give_region_a_name(errctx, renctx, region)
-            .filter(Self::region_name_is_suggestable)
-    }
-
-    /// Compiles a list of all suggestions to be printed in the final big suggestion.
-    fn compile_all_suggestions<'tcx>(
-        &self,
-        body: &Body<'tcx>,
-        region_infcx: &RegionInferenceContext<'tcx>,
-        infcx: &InferCtxt<'_, 'tcx>,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> SmallVec<[SuggestedConstraint; 2]> {
-        let mut suggested = SmallVec::new();
-
-        // Keep track of variables that we have already suggested unifying so that we don't print
-        // out silly duplicate messages.
-        let mut unified_already = FxHashSet::default();
-
-        let errctx = ErrorReportingCtx {
-            region_infcx,
-            infcx,
-            body,
-            mir_def_id: self.mir_def_id,
-            local_names: self.local_names,
-
-            // We should not be suggesting naming upvars, so we pass in a dummy set of upvars that
-            // should never be used.
-            upvars: &[],
-        };
-
-        for (fr, outlived) in &self.constraints_to_add {
-            let fr_name = if let Some(fr_name) = self.region_vid_to_name(&errctx, renctx, *fr) {
-                fr_name
-            } else {
-                continue;
-            };
-
-            let outlived = outlived
-                .iter()
-                // if there is a `None`, we will just omit that constraint
-                .filter_map(|fr| {
-                    self.region_vid_to_name(&errctx, renctx, *fr).map(|rname| (fr, rname))
-                })
-                .collect::<Vec<_>>();
-
-            // No suggestable outlived lifetimes.
-            if outlived.is_empty() {
-                continue;
-            }
-
-            // There are three types of suggestions we can make:
-            // 1) Suggest a bound: 'a: 'b
-            // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we
-            //    should just replace 'a with 'static.
-            // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a
-
-            if outlived.iter().any(|(_, outlived_name)| {
-                if let RegionNameSource::Static = outlived_name.source {
-                    true
-                } else {
-                    false
-                }
-            }) {
-                suggested.push(SuggestedConstraint::Static(fr_name));
-            } else {
-                // We want to isolate out all lifetimes that should be unified and print out
-                // separate messages for them.
-
-                let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition(
-                    // Do we have both 'fr: 'r and 'r: 'fr?
-                    |(r, _)| {
-                        self.constraints_to_add
-                            .get(r)
-                            .map(|r_outlived| r_outlived.as_slice().contains(fr))
-                            .unwrap_or(false)
-                    },
-                );
-
-                for (r, bound) in unified.into_iter() {
-                    if !unified_already.contains(fr) {
-                        suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound));
-                        unified_already.insert(r);
-                    }
-                }
-
-                if !other.is_empty() {
-                    let other =
-                        other.iter().map(|(_, rname)| rname.clone()).collect::<SmallVec<_>>();
-                    suggested.push(SuggestedConstraint::Outlives(fr_name, other))
-                }
-            }
-        }
-
-        suggested
-    }
-
-    /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest.
-    crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) {
-        debug!("Collected {:?}: {:?}", fr, outlived_fr);
-
-        // Add to set of constraints for final help note.
-        self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr);
-    }
-
-    /// Emit an intermediate note on the given `Diagnostic` if the involved regions are
-    /// suggestable.
-    crate fn intermediate_suggestion(
-        &mut self,
-        errctx: &ErrorReportingCtx<'_, '_, '_>,
-        errci: &ErrorConstraintInfo,
-        renctx: &mut RegionErrorNamingCtx,
-        diag: &mut DiagnosticBuilder<'_>,
-    ) {
-        // Emit an intermediate note.
-        let fr_name = self.region_vid_to_name(errctx, renctx, errci.fr);
-        let outlived_fr_name = self.region_vid_to_name(errctx, renctx, errci.outlived_fr);
-
-        if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) {
-            if let RegionNameSource::Static = outlived_fr_name.source {
-                diag.help(&format!("consider replacing `{}` with `'static`", fr_name));
-            } else {
-                diag.help(&format!(
-                    "consider adding the following bound: `{}: {}`",
-                    fr_name, outlived_fr_name
-                ));
-            }
-        }
-    }
-
-    /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final
-    /// suggestion including all collected constraints.
-    crate fn add_suggestion<'tcx>(
-        &self,
-        body: &Body<'tcx>,
-        region_infcx: &RegionInferenceContext<'tcx>,
-        infcx: &InferCtxt<'_, 'tcx>,
-        errors_buffer: &mut Vec<Diagnostic>,
-        renctx: &mut RegionErrorNamingCtx,
-    ) {
-        // No constraints to add? Done.
-        if self.constraints_to_add.is_empty() {
-            debug!("No constraints to suggest.");
-            return;
-        }
-
-        // If there is only one constraint to suggest, then we already suggested it in the
-        // intermediate suggestion above.
-        if self.constraints_to_add.len() == 1 {
-            debug!("Only 1 suggestion. Skipping.");
-            return;
-        }
-
-        // Get all suggestable constraints.
-        let suggested = self.compile_all_suggestions(body, region_infcx, infcx, renctx);
-
-        // If there are no suggestable constraints...
-        if suggested.is_empty() {
-            debug!("Only 1 suggestable constraint. Skipping.");
-            return;
-        }
-
-        // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
-        // list of diagnostics.
-        let mut diag = if suggested.len() == 1 {
-            infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
-                SuggestedConstraint::Outlives(a, bs) => {
-                    let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect();
-                    format!("add bound `{}: {}`", a, bs.join(" + "))
-                }
-
-                SuggestedConstraint::Equal(a, b) => {
-                    format!("`{}` and `{}` must be the same: replace one with the other", a, b)
-                }
-                SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a),
-            })
-        } else {
-            // Create a new diagnostic.
-            let mut diag = infcx
-                .tcx
-                .sess
-                .diagnostic()
-                .struct_help("the following changes may resolve your lifetime errors");
-
-            // Add suggestions.
-            for constraint in suggested {
-                match constraint {
-                    SuggestedConstraint::Outlives(a, bs) => {
-                        let bs: SmallVec<[String; 2]> =
-                            bs.iter().map(|r| format!("{}", r)).collect();
-                        diag.help(&format!("add bound `{}: {}`", a, bs.join(" + ")));
-                    }
-                    SuggestedConstraint::Equal(a, b) => {
-                        diag.help(&format!(
-                            "`{}` and `{}` must be the same: replace one with the other",
-                            a, b
-                        ));
-                    }
-                    SuggestedConstraint::Static(a) => {
-                        diag.help(&format!("replace `{}` with `'static`", a));
-                    }
-                }
-            }
-
-            diag
-        };
-
-        // We want this message to appear after other messages on the mir def.
-        let mir_span = infcx.tcx.def_span(self.mir_def_id);
-        diag.sort_span = mir_span.shrink_to_hi();
-
-        // Buffer the diagnostic
-        diag.buffer(errors_buffer);
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
deleted file mode 100644 (file)
index 0f5d1c5..0000000
+++ /dev/null
@@ -1,834 +0,0 @@
-use std::fmt::{self, Display};
-
-use crate::borrow_check::nll::region_infer::{
-    RegionInferenceContext,
-    error_reporting::ErrorReportingCtx,
-};
-use crate::borrow_check::nll::universal_regions::DefiningTy;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::Upvar;
-use rustc::hir;
-use rustc::hir::def::{Res, DefKind};
-use rustc::hir::def_id::DefId;
-use rustc::infer::InferCtxt;
-use rustc::mir::{Local, Body};
-use rustc::ty::subst::{SubstsRef, GenericArgKind};
-use rustc::ty::{self, RegionVid, Ty, TyCtxt};
-use rustc::ty::print::RegionHighlightMode;
-use rustc_index::vec::IndexVec;
-use rustc_errors::DiagnosticBuilder;
-use syntax::symbol::kw;
-use rustc_data_structures::fx::FxHashMap;
-use syntax_pos::{Span, symbol::Symbol, DUMMY_SP};
-
-/// A name for a particular region used in emitting diagnostics. This name could be a generated
-/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
-#[derive(Debug, Clone)]
-crate struct RegionName {
-    /// The name of the region (interned).
-    crate name: Symbol,
-    /// Where the region comes from.
-    crate source: RegionNameSource,
-}
-
-/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
-/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`.
-/// This helps to print the right kinds of diagnostics.
-#[derive(Debug, Clone)]
-crate enum RegionNameSource {
-    /// A bound (not free) region that was substituted at the def site (not an HRTB).
-    NamedEarlyBoundRegion(Span),
-    /// A free region that the user has a name (`'a`) for.
-    NamedFreeRegion(Span),
-    /// The `'static` region.
-    Static,
-    /// The free region corresponding to the environment of a closure.
-    SynthesizedFreeEnvRegion(Span, String),
-    /// The region name corresponds to a region where the type annotation is completely missing
-    /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
-    CannotMatchHirTy(Span, String),
-    /// The region name corresponds a reference that was found by traversing the type in the HIR.
-    MatchedHirTy(Span),
-    /// A region name from the generics list of a struct/enum/union.
-    MatchedAdtAndSegment(Span),
-    /// The region corresponding to a closure upvar.
-    AnonRegionFromUpvar(Span, String),
-    /// The region corresponding to the return type of a closure.
-    AnonRegionFromOutput(Span, String, String),
-    /// The region from a type yielded by a generator.
-    AnonRegionFromYieldTy(Span, String),
-    /// An anonymous region from an async fn.
-    AnonRegionFromAsyncFn(Span),
-}
-
-/// Records region names that have been assigned before so that we can use the same ones in later
-/// diagnostics.
-#[derive(Debug, Clone)]
-crate struct RegionErrorNamingCtx {
-    /// Record the region names generated for each region in the given
-    /// MIR def so that we can reuse them later in help/error messages.
-    renctx: FxHashMap<RegionVid, RegionName>,
-
-    /// The counter for generating new region names.
-    counter: usize,
-}
-
-impl RegionErrorNamingCtx {
-    crate fn new() -> Self {
-        Self {
-            counter: 1,
-            renctx: FxHashMap::default(),
-        }
-    }
-
-    /// Get the name of `region` if it has previously been named.
-    crate fn get(&self, region: &RegionVid) -> Option<&RegionName> {
-        self.renctx.get(region)
-    }
-
-    /// Give `region` the name `name`.
-    crate fn insert(&mut self, region: RegionVid, name: RegionName) {
-        self.renctx.insert(region, name);
-    }
-
-    /// Creates a synthetic region named `'N`, where `N` is the next value of the counter. Then,
-    /// increment the counter.
-    ///
-    /// The name is not memoized. A separate call to `insert` should be made later. (Currently,
-    /// this happens at the end of `give_region_a_name`).
-    crate fn synthesize_region_name(&mut self) -> Symbol {
-        let c = self.counter;
-        self.counter += 1;
-
-        Symbol::intern(&format!("'{:?}", c))
-    }
-}
-
-impl RegionName {
-    crate fn was_named(&self) -> bool {
-        match self.source {
-            RegionNameSource::NamedEarlyBoundRegion(..) |
-            RegionNameSource::NamedFreeRegion(..) |
-            RegionNameSource::Static => true,
-            RegionNameSource::SynthesizedFreeEnvRegion(..) |
-            RegionNameSource::CannotMatchHirTy(..) |
-            RegionNameSource::MatchedHirTy(..) |
-            RegionNameSource::MatchedAdtAndSegment(..) |
-            RegionNameSource::AnonRegionFromUpvar(..) |
-            RegionNameSource::AnonRegionFromOutput(..) |
-            RegionNameSource::AnonRegionFromYieldTy(..) |
-            RegionNameSource::AnonRegionFromAsyncFn(..) => false,
-        }
-    }
-
-    crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
-        match &self.source {
-            RegionNameSource::NamedFreeRegion(span)
-            | RegionNameSource::NamedEarlyBoundRegion(span) => {
-                diag.span_label(*span, format!("lifetime `{}` defined here", self));
-            }
-            RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
-                diag.span_label(
-                    *span,
-                    format!("lifetime `{}` represents this closure's body", self),
-                );
-                diag.note(&note);
-            }
-            RegionNameSource::CannotMatchHirTy(span, type_name) => {
-                diag.span_label(*span, format!("has type `{}`", type_name));
-            }
-            RegionNameSource::MatchedHirTy(span) |
-            RegionNameSource::AnonRegionFromAsyncFn(span) => {
-                diag.span_label(
-                    *span,
-                    format!("let's call the lifetime of this reference `{}`", self),
-                );
-            }
-            RegionNameSource::MatchedAdtAndSegment(span) => {
-                diag.span_label(*span, format!("let's call this `{}`", self));
-            }
-            RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
-                diag.span_label(
-                    *span,
-                    format!(
-                        "lifetime `{}` appears in the type of `{}`",
-                        self, upvar_name
-                    ),
-                );
-            }
-            RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => {
-                diag.span_label(
-                    *span,
-                    format!("return type{} is {}", mir_description, type_name),
-                );
-            },
-            RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
-                diag.span_label(
-                    *span,
-                    format!("yield type is {}", type_name),
-                );
-            }
-            RegionNameSource::Static => {},
-        }
-    }
-}
-
-impl Display for RegionName {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.name)
-    }
-}
-
-impl<'tcx> RegionInferenceContext<'tcx> {
-    /// Maps from an internal MIR region vid to something that we can
-    /// report to the user. In some cases, the region vids will map
-    /// directly to lifetimes that the user has a name for (e.g.,
-    /// `'static`). But frequently they will not, in which case we
-    /// have to find some way to identify the lifetime to the user. To
-    /// that end, this function takes a "diagnostic" so that it can
-    /// create auxiliary notes as needed.
-    ///
-    /// Example (function arguments):
-    ///
-    /// Suppose we are trying to give a name to the lifetime of the
-    /// reference `x`:
-    ///
-    /// ```
-    /// fn foo(x: &u32) { .. }
-    /// ```
-    ///
-    /// This function would create a label like this:
-    ///
-    /// ```
-    ///  | fn foo(x: &u32) { .. }
-    ///           ------- fully elaborated type of `x` is `&'1 u32`
-    /// ```
-    ///
-    /// and then return the name `'1` for us to use.
-    crate fn give_region_a_name(
-        &self,
-        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
-        renctx: &mut RegionErrorNamingCtx,
-        fr: RegionVid,
-    ) -> Option<RegionName> {
-        let ErrorReportingCtx {
-            infcx, body, mir_def_id, local_names, upvars, ..
-        } = errctx;
-
-        debug!("give_region_a_name(fr={:?}, counter={:?})", fr, renctx.counter);
-
-        assert!(self.universal_regions.is_universal_region(fr));
-
-        if let Some(value) = renctx.get(&fr) {
-            return Some(value.clone());
-        }
-
-        let value = self
-            .give_name_from_error_region(infcx.tcx, *mir_def_id, fr, renctx)
-            .or_else(|| {
-                self.give_name_if_anonymous_region_appears_in_arguments(
-                    infcx, body, local_names, *mir_def_id, fr, renctx,
-                )
-            })
-            .or_else(|| {
-                self.give_name_if_anonymous_region_appears_in_upvars(
-                    infcx.tcx, upvars, fr, renctx
-                )
-            })
-            .or_else(|| {
-                self.give_name_if_anonymous_region_appears_in_output(
-                    infcx, body, *mir_def_id, fr, renctx,
-                )
-            })
-            .or_else(|| {
-                self.give_name_if_anonymous_region_appears_in_yield_ty(
-                    infcx, body, *mir_def_id, fr, renctx,
-                )
-            });
-
-        if let Some(ref value) = value {
-            renctx.insert(fr, value.clone());
-        }
-
-        debug!("give_region_a_name: gave name {:?}", value);
-        value
-    }
-
-    /// Checks for the case where `fr` maps to something that the
-    /// *user* has a name for. In that case, we'll be able to map
-    /// `fr` to a `Region<'tcx>`, and that region will be one of
-    /// named variants.
-    fn give_name_from_error_region(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        let error_region = self.to_error_region(fr)?;
-
-        debug!("give_region_a_name: error_region = {:?}", error_region);
-        match error_region {
-            ty::ReEarlyBound(ebr) => {
-                if ebr.has_name() {
-                    let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
-                    Some(RegionName {
-                        name: ebr.name,
-                        source: RegionNameSource::NamedEarlyBoundRegion(span),
-                    })
-                } else {
-                    None
-                }
-            }
-
-            ty::ReStatic => Some(RegionName {
-                name: kw::StaticLifetime,
-                source: RegionNameSource::Static
-            }),
-
-            ty::ReFree(free_region) => match free_region.bound_region {
-                ty::BoundRegion::BrNamed(region_def_id, name) => {
-                    // Get the span to point to, even if we don't use the name.
-                    let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
-                    debug!("bound region named: {:?}, is_named: {:?}",
-                        name, free_region.bound_region.is_named());
-
-                    if free_region.bound_region.is_named() {
-                        // A named region that is actually named.
-                        Some(RegionName {
-                            name,
-                            source: RegionNameSource::NamedFreeRegion(span),
-                        })
-                    } else {
-                        // If we spuriously thought that the region is named, we should let the
-                        // system generate a true name for error messages. Currently this can
-                        // happen if we have an elided name in an async fn for example: the
-                        // compiler will generate a region named `'_`, but reporting such a name is
-                        // not actually useful, so we synthesize a name for it instead.
-                        let name = renctx.synthesize_region_name();
-                        Some(RegionName {
-                            name,
-                            source: RegionNameSource::AnonRegionFromAsyncFn(span),
-                        })
-                    }
-                }
-
-                ty::BoundRegion::BrEnv => {
-                    let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
-                    let def_ty = self.universal_regions.defining_ty;
-
-                    if let DefiningTy::Closure(def_id, substs) = def_ty {
-                        let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
-                            tcx.hir().expect_expr(mir_hir_id).kind
-                        {
-                            span
-                        } else {
-                            bug!("Closure is not defined by a closure expr");
-                        };
-                        let region_name = renctx.synthesize_region_name();
-
-                        let closure_kind_ty = substs.as_closure().kind_ty(def_id, tcx);
-                        let note = match closure_kind_ty.to_opt_closure_kind() {
-                            Some(ty::ClosureKind::Fn) => {
-                                "closure implements `Fn`, so references to captured variables \
-                                 can't escape the closure"
-                            }
-                            Some(ty::ClosureKind::FnMut) => {
-                                "closure implements `FnMut`, so references to captured variables \
-                                 can't escape the closure"
-                            }
-                            Some(ty::ClosureKind::FnOnce) => {
-                                bug!("BrEnv in a `FnOnce` closure");
-                            }
-                            None => bug!("Closure kind not inferred in borrow check"),
-                        };
-
-                        Some(RegionName {
-                            name: region_name,
-                            source: RegionNameSource::SynthesizedFreeEnvRegion(
-                                args_span,
-                                note.to_string(),
-                            ),
-                        })
-                    } else {
-                        // Can't have BrEnv in functions, constants or generators.
-                        bug!("BrEnv outside of closure.");
-                    }
-                }
-
-                ty::BoundRegion::BrAnon(_) => None,
-            },
-
-            ty::ReLateBound(..)
-            | ty::ReScope(..)
-            | ty::ReVar(..)
-            | ty::RePlaceholder(..)
-            | ty::ReEmpty
-            | ty::ReErased
-            | ty::ReClosureBound(..) => None,
-        }
-    }
-
-    /// Finds an argument that contains `fr` and label it with a fully
-    /// elaborated type, returning something like `'1`. Result looks
-    /// like:
-    ///
-    /// ```
-    ///  | fn foo(x: &u32) { .. }
-    ///           ------- fully elaborated type of `x` is `&'1 u32`
-    /// ```
-    fn give_name_if_anonymous_region_appears_in_arguments(
-        &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        body: &Body<'tcx>,
-        local_names: &IndexVec<Local, Option<Symbol>>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
-        let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
-
-        let arg_ty =
-            self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
-        if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument(
-            infcx,
-            mir_def_id,
-            fr,
-            arg_ty,
-            argument_index,
-            renctx,
-        ) {
-            return Some(region_name);
-        }
-
-        self.give_name_if_we_cannot_match_hir_ty(infcx, body, local_names, fr, arg_ty, renctx)
-    }
-
-    fn give_name_if_we_can_match_hir_ty_from_argument(
-        &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        mir_def_id: DefId,
-        needle_fr: RegionVid,
-        argument_ty: Ty<'tcx>,
-        argument_index: usize,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        let mir_hir_id = infcx.tcx.hir().as_local_hir_id(mir_def_id)?;
-        let fn_decl = infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
-        let argument_hir_ty: &hir::Ty = fn_decl.inputs.get(argument_index)?;
-        match argument_hir_ty.kind {
-            // This indicates a variable with no type annotation, like
-            // `|x|`... in that case, we can't highlight the type but
-            // must highlight the variable.
-            // NOTE(eddyb) this is handled in/by the sole caller
-            // (`give_name_if_anonymous_region_appears_in_arguments`).
-            hir::TyKind::Infer => None,
-
-            _ => self.give_name_if_we_can_match_hir_ty(
-                infcx.tcx,
-                needle_fr,
-                argument_ty,
-                argument_hir_ty,
-                renctx,
-            ),
-        }
-    }
-
-    /// Attempts to highlight the specific part of a type in an argument
-    /// that has no type annotation.
-    /// For example, we might produce an annotation like this:
-    ///
-    /// ```
-    ///  |     foo(|a, b| b)
-    ///  |          -  -
-    ///  |          |  |
-    ///  |          |  has type `&'1 u32`
-    ///  |          has type `&'2 u32`
-    /// ```
-    fn give_name_if_we_cannot_match_hir_ty(
-        &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        body: &Body<'tcx>,
-        local_names: &IndexVec<Local, Option<Symbol>>,
-        needle_fr: RegionVid,
-        argument_ty: Ty<'tcx>,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        let counter = renctx.counter;
-        let mut highlight = RegionHighlightMode::default();
-        highlight.highlighting_region_vid(needle_fr, counter);
-        let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)).0;
-
-        debug!(
-            "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
-            type_name, needle_fr
-        );
-        let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
-            // Only add a label if we can confirm that a region was labelled.
-            let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
-            let (_, span) =
-                self.get_argument_name_and_span_for_region(body, local_names, argument_index);
-
-            Some(RegionName {
-                // This counter value will already have been used, so this function will increment
-                // it so the next value will be used next and return the region name that would
-                // have been used.
-                name: renctx.synthesize_region_name(),
-                source: RegionNameSource::CannotMatchHirTy(span, type_name),
-            })
-        } else {
-            None
-        };
-
-        assigned_region_name
-    }
-
-    /// Attempts to highlight the specific part of a type annotation
-    /// that contains the anonymous reference we want to give a name
-    /// to. For example, we might produce an annotation like this:
-    ///
-    /// ```
-    ///  | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item = &T>> {
-    ///  |                - let's call the lifetime of this reference `'1`
-    /// ```
-    ///
-    /// the way this works is that we match up `argument_ty`, which is
-    /// a `Ty<'tcx>` (the internal form of the type) with
-    /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
-    /// annotation). We are descending through the types stepwise,
-    /// looking in to find the region `needle_fr` in the internal
-    /// type. Once we find that, we can use the span of the `hir::Ty`
-    /// to add the highlight.
-    ///
-    /// This is a somewhat imperfect process, so along the way we also
-    /// keep track of the **closest** type we've found. If we fail to
-    /// find the exact `&` or `'_` to highlight, then we may fall back
-    /// to highlighting that closest type instead.
-    fn give_name_if_we_can_match_hir_ty(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        needle_fr: RegionVid,
-        argument_ty: Ty<'tcx>,
-        argument_hir_ty: &hir::Ty,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> =
-            &mut vec![(argument_ty, argument_hir_ty)];
-
-        while let Some((ty, hir_ty)) = search_stack.pop() {
-            match (&ty.kind, &hir_ty.kind) {
-                // Check if the `argument_ty` is `&'X ..` where `'X`
-                // is the region we are looking for -- if so, and we have a `&T`
-                // on the RHS, then we want to highlight the `&` like so:
-                //
-                //     &
-                //     - let's call the lifetime of this reference `'1`
-                (
-                    ty::Ref(region, referent_ty, _),
-                    hir::TyKind::Rptr(_lifetime, referent_hir_ty),
-                ) => {
-                    if region.to_region_vid() == needle_fr {
-                        let region_name = renctx.synthesize_region_name();
-
-                        // Just grab the first character, the `&`.
-                        let source_map = tcx.sess.source_map();
-                        let ampersand_span = source_map.start_point(hir_ty.span);
-
-                        return Some(RegionName {
-                            name: region_name,
-                            source: RegionNameSource::MatchedHirTy(ampersand_span),
-                        });
-                    }
-
-                    // Otherwise, let's descend into the referent types.
-                    search_stack.push((referent_ty, &referent_hir_ty.ty));
-                }
-
-                // Match up something like `Foo<'1>`
-                (
-                    ty::Adt(_adt_def, substs),
-                    hir::TyKind::Path(hir::QPath::Resolved(None, path)),
-                ) => {
-                    match path.res {
-                        // Type parameters of the type alias have no reason to
-                        // be the same as those of the ADT.
-                        // FIXME: We should be able to do something similar to
-                        // match_adt_and_segment in this case.
-                        Res::Def(DefKind::TyAlias, _) => (),
-                        _ => if let Some(last_segment) = path.segments.last() {
-                            if let Some(name) = self.match_adt_and_segment(
-                                substs,
-                                needle_fr,
-                                last_segment,
-                                renctx,
-                                search_stack,
-                            ) {
-                                return Some(name);
-                            }
-                        }
-                    }
-                }
-
-                // The following cases don't have lifetimes, so we
-                // just worry about trying to match up the rustc type
-                // with the HIR types:
-                (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
-                    search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(elem_hir_tys));
-                }
-
-                (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
-                | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => {
-                    search_stack.push((elem_ty, elem_hir_ty));
-                }
-
-                (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => {
-                    search_stack.push((mut_ty.ty, &mut_hir_ty.ty));
-                }
-
-                _ => {
-                    // FIXME there are other cases that we could trace
-                }
-            }
-        }
-
-        return None;
-    }
-
-    /// We've found an enum/struct/union type with the substitutions
-    /// `substs` and -- in the HIR -- a path type with the final
-    /// segment `last_segment`. Try to find a `'_` to highlight in
-    /// the generic args (or, if not, to produce new zipped pairs of
-    /// types+hir to search through).
-    fn match_adt_and_segment<'hir>(
-        &self,
-        substs: SubstsRef<'tcx>,
-        needle_fr: RegionVid,
-        last_segment: &'hir hir::PathSegment,
-        renctx: &mut RegionErrorNamingCtx,
-        search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
-    ) -> Option<RegionName> {
-        // Did the user give explicit arguments? (e.g., `Foo<..>`)
-        let args = last_segment.args.as_ref()?;
-        let lifetime =
-            self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
-        match lifetime.name {
-            hir::LifetimeName::Param(_)
-            | hir::LifetimeName::Error
-            | hir::LifetimeName::Static
-            | hir::LifetimeName::Underscore => {
-                let region_name = renctx.synthesize_region_name();
-                let ampersand_span = lifetime.span;
-                Some(RegionName {
-                    name: region_name,
-                    source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
-                })
-            }
-
-            hir::LifetimeName::ImplicitObjectLifetimeDefault
-            | hir::LifetimeName::Implicit => {
-                // In this case, the user left off the lifetime; so
-                // they wrote something like:
-                //
-                // ```
-                // x: Foo<T>
-                // ```
-                //
-                // where the fully elaborated form is `Foo<'_, '1,
-                // T>`. We don't consider this a match; instead we let
-                // the "fully elaborated" type fallback above handle
-                // it.
-                None
-            }
-        }
-    }
-
-    /// We've found an enum/struct/union type with the substitutions
-    /// `substs` and -- in the HIR -- a path with the generic
-    /// arguments `args`. If `needle_fr` appears in the args, return
-    /// the `hir::Lifetime` that corresponds to it. If not, push onto
-    /// `search_stack` the types+hir to search through.
-    fn try_match_adt_and_generic_args<'hir>(
-        &self,
-        substs: SubstsRef<'tcx>,
-        needle_fr: RegionVid,
-        args: &'hir hir::GenericArgs,
-        search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
-    ) -> Option<&'hir hir::Lifetime> {
-        for (kind, hir_arg) in substs.iter().zip(&args.args) {
-            match (kind.unpack(), hir_arg) {
-                (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
-                    if r.to_region_vid() == needle_fr {
-                        return Some(lt);
-                    }
-                }
-
-                (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
-                    search_stack.push((ty, hir_ty));
-                }
-
-                (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
-                    // Lifetimes cannot be found in consts, so we don't need
-                    // to search anything here.
-                }
-
-                (GenericArgKind::Lifetime(_), _)
-                | (GenericArgKind::Type(_), _)
-                | (GenericArgKind::Const(_), _) => {
-                    // I *think* that HIR lowering should ensure this
-                    // doesn't happen, even in erroneous
-                    // programs. Else we should use delay-span-bug.
-                    span_bug!(
-                        hir_arg.span(),
-                        "unmatched subst and hir arg: found {:?} vs {:?}",
-                        kind,
-                        hir_arg,
-                    );
-                }
-            }
-        }
-
-        None
-    }
-
-    /// Finds a closure upvar that contains `fr` and label it with a
-    /// fully elaborated type, returning something like `'1`. Result
-    /// looks like:
-    ///
-    /// ```
-    ///  | let x = Some(&22);
-    ///        - fully elaborated type of `x` is `Option<&'1 u32>`
-    /// ```
-    fn give_name_if_anonymous_region_appears_in_upvars(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        upvars: &[Upvar],
-        fr: RegionVid,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
-        let (upvar_name, upvar_span) =
-            self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index);
-        let region_name = renctx.synthesize_region_name();
-
-        Some(RegionName {
-            name: region_name,
-            source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()),
-        })
-    }
-
-    /// Checks for arguments appearing in the (closure) return type. It
-    /// must be a closure since, in a free fn, such an argument would
-    /// have to either also appear in an argument (if using elision)
-    /// or be early bound (named, not in argument).
-    fn give_name_if_anonymous_region_appears_in_output(
-        &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        body: &Body<'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        let tcx = infcx.tcx;
-
-        let return_ty = self.universal_regions.unnormalized_output_ty;
-        debug!(
-            "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}",
-            return_ty
-        );
-        if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
-            return None;
-        }
-
-        let mut highlight = RegionHighlightMode::default();
-        highlight.highlighting_region_vid(fr, renctx.counter);
-        let type_name = infcx.extract_type_name(&return_ty, Some(highlight)).0;
-
-        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
-
-        let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) {
-            hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(_, return_ty, _, span, gen_move),
-                ..
-            }) => (
-                match return_ty.output {
-                    hir::FunctionRetTy::DefaultReturn(_) => tcx.sess.source_map().end_point(*span),
-                    hir::FunctionRetTy::Return(_) => return_ty.output.span(),
-                },
-                if gen_move.is_some() {
-                    " of generator"
-                } else {
-                    " of closure"
-                },
-            ),
-            hir::Node::ImplItem(hir::ImplItem {
-                kind: hir::ImplItemKind::Method(method_sig, _),
-                ..
-            }) => (method_sig.decl.output.span(), ""),
-            _ => (body.span, ""),
-        };
-
-        Some(RegionName {
-            // This counter value will already have been used, so this function will increment it
-            // so the next value will be used next and return the region name that would have been
-            // used.
-            name: renctx.synthesize_region_name(),
-            source: RegionNameSource::AnonRegionFromOutput(
-                return_span,
-                mir_description.to_string(),
-                type_name,
-            ),
-        })
-    }
-
-    fn give_name_if_anonymous_region_appears_in_yield_ty(
-        &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        body: &Body<'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        renctx: &mut RegionErrorNamingCtx,
-    ) -> Option<RegionName> {
-        // Note: generators from `async fn` yield `()`, so we don't have to
-        // worry about them here.
-        let yield_ty = self.universal_regions.yield_ty?;
-        debug!(
-            "give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}",
-            yield_ty,
-        );
-
-        let tcx = infcx.tcx;
-
-        if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
-            return None;
-        }
-
-        let mut highlight = RegionHighlightMode::default();
-        highlight.highlighting_region_vid(fr, renctx.counter);
-        let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)).0;
-
-        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
-
-        let yield_span = match tcx.hir().get(mir_hir_id) {
-            hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(_, _, _, span, _),
-                ..
-            }) => (
-                tcx.sess.source_map().end_point(*span)
-            ),
-            _ => body.span,
-        };
-
-        debug!(
-            "give_name_if_anonymous_region_appears_in_yield_ty: \
-             type_name = {:?}, yield_span = {:?}",
-            yield_span,
-            type_name,
-        );
-
-        Some(RegionName {
-            name: renctx.synthesize_region_name(),
-            source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
-        })
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs
deleted file mode 100644 (file)
index 1ac44c4..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::Upvar;
-use rustc::mir::{Local, Body};
-use rustc::ty::{RegionVid, TyCtxt};
-use rustc_index::vec::{Idx, IndexVec};
-use syntax::source_map::Span;
-use syntax_pos::symbol::Symbol;
-
-impl<'tcx> RegionInferenceContext<'tcx> {
-    crate fn get_var_name_and_span_for_region(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
-        local_names: &IndexVec<Local, Option<Symbol>>,
-        upvars: &[Upvar],
-        fr: RegionVid,
-    ) -> Option<(Option<Symbol>, Span)> {
-        debug!("get_var_name_and_span_for_region(fr={:?})", fr);
-        assert!(self.universal_regions.is_universal_region(fr));
-
-        debug!("get_var_name_and_span_for_region: attempting upvar");
-        self.get_upvar_index_for_region(tcx, fr)
-            .map(|index| {
-                let (name, span) =
-                    self.get_upvar_name_and_span_for_region(tcx, upvars, index);
-                (Some(name), span)
-            })
-            .or_else(|| {
-                debug!("get_var_name_and_span_for_region: attempting argument");
-                self.get_argument_index_for_region(tcx, fr).map(|index| {
-                    self.get_argument_name_and_span_for_region(body, local_names, index)
-                })
-            })
-    }
-
-    /// Search the upvars (if any) to find one that references fr. Return its index.
-    crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option<usize> {
-        let upvar_index = self
-            .universal_regions
-            .defining_ty
-            .upvar_tys(tcx)
-            .position(|upvar_ty| {
-                debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
-                tcx.any_free_region_meets(&upvar_ty, |r| {
-                    let r = r.to_region_vid();
-                    debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr);
-                    r == fr
-                })
-            })?;
-
-        let upvar_ty = self
-            .universal_regions
-            .defining_ty
-            .upvar_tys(tcx)
-            .nth(upvar_index);
-
-        debug!(
-            "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
-            fr, upvar_index, upvar_ty,
-        );
-
-        Some(upvar_index)
-    }
-
-    /// Given the index of an upvar, finds its name and the span from where it was
-    /// declared.
-    crate fn get_upvar_name_and_span_for_region(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        upvars: &[Upvar],
-        upvar_index: usize,
-    ) -> (Symbol, Span) {
-        let upvar_hir_id = upvars[upvar_index].var_hir_id;
-        debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id);
-
-        let upvar_name = tcx.hir().name(upvar_hir_id);
-        let upvar_span = tcx.hir().span(upvar_hir_id);
-        debug!("get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}",
-               upvar_name, upvar_span);
-
-        (upvar_name, upvar_span)
-    }
-
-    /// Search the argument types for one that references fr (which should be a free region).
-    /// Returns Some(_) with the index of the input if one is found.
-    ///
-    /// N.B., in the case of a closure, the index is indexing into the signature as seen by the
-    /// user - in particular, index 0 is not the implicit self parameter.
-    crate fn get_argument_index_for_region(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        fr: RegionVid,
-    ) -> Option<usize> {
-        let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
-        let argument_index = self
-            .universal_regions
-            .unnormalized_input_tys
-            .iter()
-            .skip(implicit_inputs)
-            .position(|arg_ty| {
-                debug!(
-                    "get_argument_index_for_region: arg_ty = {:?}",
-                    arg_ty
-                );
-                tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
-            })?;
-
-        debug!(
-            "get_argument_index_for_region: found {:?} in argument {} which has type {:?}",
-            fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index],
-        );
-
-        Some(argument_index)
-    }
-
-    /// Given the index of an argument, finds its name (if any) and the span from where it was
-    /// declared.
-    crate fn get_argument_name_and_span_for_region(
-        &self,
-        body: &Body<'tcx>,
-        local_names: &IndexVec<Local, Option<Symbol>>,
-        argument_index: usize,
-    ) -> (Option<Symbol>, Span) {
-        let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
-        let argument_local = Local::new(implicit_inputs + argument_index + 1);
-        debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
-
-        let argument_name = local_names[argument_local];
-        let argument_span = body.local_decls[argument_local].source_info.span;
-        debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
-               argument_name, argument_span);
-
-        (argument_name, argument_span)
-    }
-}
index bd9e97e5b633b6fca17f68e0fd77efb45aae06c5..85031d6210a4d2202bbc4dab2c2d66affd5753f6 100644 (file)
@@ -1,21 +1,5 @@
 use std::rc::Rc;
 
-use crate::borrow_check::nll::{
-    constraints::{
-        graph::NormalConstraintGraph,
-        ConstraintSccIndex,
-        OutlivesConstraint,
-        OutlivesConstraintSet,
-    },
-    member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
-    region_infer::values::{
-        PlaceholderIndices, RegionElement, ToElementIndex
-    },
-    region_infer::error_reporting::outlives_suggestion::OutlivesSuggestionBuilder,
-    type_check::{free_region_relations::UniversalRegionRelations, Locations},
-};
-use crate::borrow_check::Upvar;
-
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryOutlivesConstraint;
 use rustc::infer::opaque_types;
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 
-crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx};
+use crate::borrow_check::{
+    nll::{
+        constraints::{
+            graph::NormalConstraintGraph,
+            ConstraintSccIndex,
+            OutlivesConstraint,
+            OutlivesConstraintSet,
+        },
+        member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
+        region_infer::values::{
+            PlaceholderIndices, RegionElement, ToElementIndex
+        },
+        type_check::{free_region_relations::UniversalRegionRelations, Locations},
+    },
+    diagnostics::{
+        OutlivesSuggestionBuilder, RegionErrorNamingCtx,
+    },
+    Upvar,
+};
+
 use self::values::{LivenessValues, RegionValueElements, RegionValues};
 use super::universal_regions::UniversalRegions;
 use super::ToRegionVid;
 
 mod dump_mir;
-mod error_reporting;
 mod graphviz;
 
 pub mod values;
@@ -54,48 +56,51 @@ pub struct RegionInferenceContext<'tcx> {
     /// variables are identified by their index (`RegionVid`). The
     /// definition contains information about where the region came
     /// from as well as its final inferred value.
-    definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
+    pub(in crate::borrow_check) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
 
     /// The liveness constraints added to each region. For most
     /// regions, these start out empty and steadily grow, though for
     /// each universally quantified region R they start out containing
     /// the entire CFG and `end(R)`.
-    liveness_constraints: LivenessValues<RegionVid>,
+    pub(in crate::borrow_check) liveness_constraints: LivenessValues<RegionVid>,
 
     /// The outlives constraints computed by the type-check.
-    constraints: Rc<OutlivesConstraintSet>,
+    pub(in crate::borrow_check) constraints: Rc<OutlivesConstraintSet>,
 
     /// The constraint-set, but in graph form, making it easy to traverse
     /// the constraints adjacent to a particular region. Used to construct
     /// the SCC (see `constraint_sccs`) and for error reporting.
-    constraint_graph: Rc<NormalConstraintGraph>,
+    pub(in crate::borrow_check) constraint_graph: Rc<NormalConstraintGraph>,
 
     /// The SCC computed from `constraints` and the constraint
     /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
     /// compute the values of each region.
-    constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
+    pub(in crate::borrow_check) constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
 
     /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
     /// exists if `B: A`. Computed lazilly.
-    rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
+    pub(in crate::borrow_check) rev_constraint_graph:
+        Option<Rc<VecGraph<ConstraintSccIndex>>>,
 
     /// The "R0 member of [R1..Rn]" constraints, indexed by SCC.
-    member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
+    pub(in crate::borrow_check) member_constraints:
+        Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
 
     /// Records the member constraints that we applied to each scc.
     /// This is useful for error reporting. Once constraint
     /// propagation is done, this vector is sorted according to
     /// `member_region_scc`.
-    member_constraints_applied: Vec<AppliedMemberConstraint>,
+    pub(in crate::borrow_check) member_constraints_applied: Vec<AppliedMemberConstraint>,
 
     /// Map closure bounds to a `Span` that should be used for error reporting.
-    closure_bounds_mapping:
+    pub(in crate::borrow_check) closure_bounds_mapping:
         FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
     /// Contains the minimum universe of any variable within the same
     /// SCC. We will ensure that no SCC contains values that are not
     /// visible from this index.
-    scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
+    pub(in crate::borrow_check) scc_universes:
+        IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
 
     /// Contains a "representative" from each SCC. This will be the
     /// minimal RegionVid belonging to that universe. It is used as a
@@ -104,23 +109,25 @@ pub struct RegionInferenceContext<'tcx> {
     /// of its SCC and be sure that -- if they have the same repr --
     /// they *must* be equal (though not having the same repr does not
     /// mean they are unequal).
-    scc_representatives: IndexVec<ConstraintSccIndex, ty::RegionVid>,
+    pub(in crate::borrow_check) scc_representatives:
+        IndexVec<ConstraintSccIndex, ty::RegionVid>,
 
     /// The final inferred values of the region variables; we compute
     /// one value per SCC. To get the value for any given *region*,
     /// you first find which scc it is a part of.
-    scc_values: RegionValues<ConstraintSccIndex>,
+    pub(in crate::borrow_check) scc_values: RegionValues<ConstraintSccIndex>,
 
     /// Type constraints that we check after solving.
-    type_tests: Vec<TypeTest<'tcx>>,
+    pub(in crate::borrow_check) type_tests: Vec<TypeTest<'tcx>>,
 
     /// Information about the universally quantified regions in scope
     /// on this function.
-    universal_regions: Rc<UniversalRegions<'tcx>>,
+    pub (in crate::borrow_check) universal_regions: Rc<UniversalRegions<'tcx>>,
 
     /// Information about how the universally quantified regions in
     /// scope on this function relate to one another.
-    universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
+    pub(in crate::borrow_check) universal_region_relations:
+        Rc<UniversalRegionRelations<'tcx>>,
 }
 
 /// Each time that `apply_member_constraint` is successful, it appends
@@ -132,38 +139,38 @@ pub struct RegionInferenceContext<'tcx> {
 /// with `'R: 'O` where `'R` is the pick-region and `'O` is the
 /// minimal viable option.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
-struct AppliedMemberConstraint {
+pub(crate) struct AppliedMemberConstraint {
     /// The SCC that was affected. (The "member region".)
     ///
     /// The vector if `AppliedMemberConstraint` elements is kept sorted
     /// by this field.
-    member_region_scc: ConstraintSccIndex,
+    pub(in crate::borrow_check) member_region_scc: ConstraintSccIndex,
 
     /// The "best option" that `apply_member_constraint` found -- this was
     /// added as an "ad-hoc" lower-bound to `member_region_scc`.
-    min_choice: ty::RegionVid,
+    pub(in crate::borrow_check) min_choice: ty::RegionVid,
 
     /// The "member constraint index" -- we can find out details about
     /// the constraint from
     /// `set.member_constraints[member_constraint_index]`.
-    member_constraint_index: NllMemberConstraintIndex,
+    pub(in crate::borrow_check) member_constraint_index: NllMemberConstraintIndex,
 }
 
-struct RegionDefinition<'tcx> {
+pub(crate) struct RegionDefinition<'tcx> {
     /// What kind of variable is this -- a free region? existential
     /// variable? etc. (See the `NLLRegionVariableOrigin` for more
     /// info.)
-    origin: NLLRegionVariableOrigin,
+    pub(in crate::borrow_check) origin: NLLRegionVariableOrigin,
 
     /// Which universe is this region variable defined in? This is
     /// most often `ty::UniverseIndex::ROOT`, but when we encounter
     /// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create
     /// the variable for `'a` in a fresh universe that extends ROOT.
-    universe: ty::UniverseIndex,
+    pub(in crate::borrow_check) universe: ty::UniverseIndex,
 
     /// If this is 'static or an early-bound region, then this is
     /// `Some(X)` where `X` is the name of the region.
-    external_name: Option<ty::Region<'tcx>>,
+    pub(in crate::borrow_check) external_name: Option<ty::Region<'tcx>>,
 }
 
 /// N.B., the variants in `Cause` are intentionally ordered. Lower
@@ -455,7 +462,9 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
     /// Once region solving has completed, this function will return
     /// the member constraints that were applied to the value of a given
     /// region `r`. See `AppliedMemberConstraint`.
-    fn applied_member_constraints(&self, r: impl ToRegionVid) -> &[AppliedMemberConstraint] {
+    pub(in crate::borrow_check) fn applied_member_constraints(
+        &self, r: impl ToRegionVid
+    ) -> &[AppliedMemberConstraint] {
         let scc = self.constraint_sccs.scc(r.to_region_vid());
         binary_search_util::binary_search_slice(
             &self.member_constraints_applied,
index 95b3256f53a388d81a875a636fd34a3fef83e5ca..fb5cb742ab651dbd5a4af95cc6489f57c7ba8367 100644 (file)
@@ -12,12 +12,11 @@ doctest = false
 [dependencies]
 bitflags = "1.0"
 log = "0.4"
-syntax_pos = { path = "../libsyntax_pos" }
-syntax = { path = "../libsyntax" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_lexer = { path = "../librustc_lexer" }
-rustc_target = { path = "../librustc_target" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+rustc_errors = { path = "../librustc_errors" }
 rustc_error_codes = { path = "../librustc_error_codes" }
+smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+syntax_pos = { path = "../libsyntax_pos" }
+syntax = { path = "../libsyntax" }
index 1bf6e9ecbc060ec8868bd2bff9134b71c8ef8817..30e056e52d25acd58b770a1d27145e2cb81fc5fd 100644 (file)
@@ -10,6 +10,7 @@
 
 use crate::validate_attr;
 use rustc_feature::Features;
+use rustc_errors::Applicability;
 use syntax::attr::HasAttrs;
 use syntax::feature_gate::{feature_err, get_features};
 use syntax::attr;
@@ -21,7 +22,6 @@
 use syntax::util::map_in_place::MapInPlace;
 use syntax_pos::symbol::sym;
 
-use errors::Applicability;
 use smallvec::SmallVec;
 
 /// A folder that strips out items that do not belong in the current configuration.
index 5de63cb39d16b1555ab377dfad440b6caeb3d1a6..ddcfea189800413e35c77da51d2a5e70bcaeacbd 100644 (file)
@@ -1,16 +1,15 @@
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{FatalError, DiagnosticBuilder};
+use rustc_lexer::Base;
+use rustc_lexer::unescape;
 use syntax::token::{self, Token, TokenKind};
 use syntax::sess::ParseSess;
-use syntax::symbol::{sym, Symbol};
 use syntax::util::comments;
-
-use errors::{FatalError, DiagnosticBuilder};
+use syntax_pos::symbol::{sym, Symbol};
 use syntax_pos::{BytePos, Pos, Span};
-use rustc_lexer::Base;
-use rustc_lexer::unescape;
 
 use std::char;
 use std::convert::TryInto;
-use rustc_data_structures::sync::Lrc;
 use log::debug;
 
 mod tokentrees;
index 1353591308b2e9446a10a99c26b59ae31cdceeb0..5791c6396c5840b351648ee0c4438215a76e0db0 100644 (file)
@@ -1,13 +1,11 @@
-use rustc_data_structures::fx::FxHashMap;
-use syntax_pos::Span;
-
 use super::{StringReader, UnmatchedBrace};
 
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::PResult;
 use syntax::print::pprust::token_to_string;
 use syntax::token::{self, Token};
 use syntax::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint};
-
-use errors::PResult;
+use syntax_pos::Span;
 
 impl<'a> StringReader<'a> {
     crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
index 6eb995b61d3feeeb062f7388e61900d8e20f6f4c..edfebc7de94032ce457640ca893113b247db7d09 100644 (file)
@@ -2,9 +2,9 @@
 // http://www.unicode.org/Public/security/10.0.0/confusables.txt
 
 use super::StringReader;
-use errors::{Applicability, DiagnosticBuilder};
-use syntax_pos::{BytePos, Pos, Span, symbol::kw};
 use crate::token;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use syntax_pos::{BytePos, Pos, Span, symbol::kw};
 
 #[rustfmt::skip] // for line breaks
 const UNICODE_ARRAY: &[(char, &str, char)] = &[
index a22b383e5f39166dc0b558f843bfed5571c23832..a222f3f00c4633fe4a0a47f2ad8d7be6b15d6944 100644 (file)
@@ -8,7 +8,7 @@
 use syntax::token::{self, Nonterminal};
 use syntax::tokenstream::{self, TokenStream, TokenTree};
 
-use errors::{PResult, FatalError, Level, Diagnostic};
+use rustc_errors::{PResult, FatalError, Level, Diagnostic};
 use rustc_data_structures::sync::Lrc;
 use syntax_pos::{Span, SourceFile, FileName};
 
@@ -53,7 +53,7 @@ pub enum DirectoryOwnership {
 macro_rules! panictry_buffer {
     ($handler:expr, $e:expr) => ({
         use std::result::Result::{Ok, Err};
-        use errors::FatalError;
+        use rustc_errors::FatalError;
         match $e {
             Ok(e) => e,
             Err(errs) => {
index c7261404f54efda0dede24beb4e011e53703b1df..b2ae934ce64746f879ab94d8e277205cb10ebd07 100644 (file)
@@ -1,10 +1,10 @@
 use super::{SeqSep, Parser, TokenType, PathStyle};
+use rustc_errors::PResult;
 use syntax::attr;
 use syntax::ast;
 use syntax::util::comments;
 use syntax::token::{self, Nonterminal};
 use syntax_pos::{Span, Symbol};
-use errors::PResult;
 
 use log::debug;
 
index da8bf89ebf33b4724e251e104f467ad0152bc44d..ba125cacab48b78a79a7c4e4178dd89cd90d133e 100644 (file)
@@ -1,25 +1,22 @@
 use super::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType, SeqSep, Parser};
 
-use syntax::ast::{
-    self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind,
-    Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind,
-};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{self, PResult, Applicability, DiagnosticBuilder, Handler, pluralize};
+use rustc_error_codes::*;
+use syntax::ast::{self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item};
+use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
 use syntax::token::{self, TokenKind, token_can_begin_expr};
 use syntax::print::pprust;
 use syntax::ptr::P;
-use syntax::symbol::{kw, sym};
 use syntax::ThinVec;
 use syntax::util::parser::AssocOp;
 use syntax::struct_span_err;
-
-use errors::{PResult, Applicability, DiagnosticBuilder, pluralize};
-use rustc_data_structures::fx::FxHashSet;
+use syntax_pos::symbol::{kw, sym};
 use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError};
+
 use log::{debug, trace};
 use std::mem;
 
-use rustc_error_codes::*;
-
 const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments";
 
 /// Creates a placeholder argument.
@@ -61,10 +58,10 @@ pub enum Error {
 }
 
 impl Error {
-    fn span_err<S: Into<MultiSpan>>(
+    fn span_err(
         self,
-        sp: S,
-        handler: &errors::Handler,
+        sp: impl Into<MultiSpan>,
+        handler: &Handler,
     ) -> DiagnosticBuilder<'_> {
         match self {
             Error::FileNotFoundForModule {
@@ -212,7 +209,7 @@ pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
         self.sess.span_diagnostic.span_bug(sp, m)
     }
 
-    pub(super) fn diagnostic(&self) -> &'a errors::Handler {
+    pub(super) fn diagnostic(&self) -> &'a Handler {
         &self.sess.span_diagnostic
     }
 
index 1112274dc46a511524ba2ce1cf181fa285c01d59..3cd4988ce0be5a5a505d2ce6dce5a1ce6dffb8e1 100644 (file)
@@ -4,23 +4,20 @@
 use super::diagnostics::Error;
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
-use syntax::ast::{
-    self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode,
-    Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind,
-    FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit,
-};
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::{PResult, Applicability};
+use syntax::ast::{self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode};
+use syntax::ast::{Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind};
+use syntax::ast::{FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit};
 use syntax::token::{self, Token, TokenKind};
 use syntax::print::pprust;
 use syntax::ptr::P;
-use syntax::source_map::{self, Span};
 use syntax::util::classify;
 use syntax::util::literal::LitError;
 use syntax::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
-use syntax_pos::symbol::{kw, sym};
-use syntax_pos::Symbol;
-use errors::{PResult, Applicability};
+use syntax_pos::source_map::{self, Span};
+use syntax_pos::symbol::{kw, sym, Symbol};
 use std::mem;
-use rustc_data_structures::thin_vec::ThinVec;
 
 /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
 /// dropped into the token stream, which happens while parsing the result of
index ba5eafc0ed722b200582e0d0332097701370459c..32819cca42b23f3300e985efa220335125d21621 100644 (file)
@@ -1,11 +1,11 @@
 use super::Parser;
 
+use rustc_errors::PResult;
 use syntax::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute};
 use syntax::token;
 use syntax::source_map::DUMMY_SP;
 use syntax_pos::symbol::{kw, sym};
 
-use errors::PResult;
 
 impl<'a> Parser<'a> {
     /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
index 66a135274213eb78e8e03c0c8d6de0f18ba80a3e..ccf78e6402b3c06c789384c4f763c5a85640d25f 100644 (file)
@@ -3,6 +3,8 @@
 
 use crate::maybe_whole;
 
+use rustc_errors::{PResult, Applicability, DiagnosticBuilder, StashKey};
+use rustc_error_codes::*;
 use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
 use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
 use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
 use syntax::ThinVec;
 use syntax::token;
 use syntax::tokenstream::{DelimSpan, TokenTree, TokenStream};
-use syntax::source_map::{self, respan, Span};
 use syntax::struct_span_err;
 use syntax_pos::BytePos;
+use syntax_pos::source_map::{self, respan, Span};
 use syntax_pos::symbol::{kw, sym, Symbol};
 
-use rustc_error_codes::*;
-
 use log::debug;
 use std::mem;
-use errors::{PResult, Applicability, DiagnosticBuilder, StashKey};
 
 pub(super) type ItemInfo = (Ident, ItemKind, Option<Vec<Attribute>>);
 
index 28689720044e8e702f6d80fd08e912f71a2212ae..07e99cfe01292cab7ed680b28ebe1f50d019f711 100644 (file)
 use crate::{Directory, DirectoryOwnership};
 use crate::lexer::UnmatchedBrace;
 
-use syntax::ast::{
-    self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit,
-    IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety,
-};
-
+use rustc_errors::{PResult, Applicability, DiagnosticBuilder, FatalError};
+use rustc_data_structures::thin_vec::ThinVec;
+use syntax::ast::{self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit};
+use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety};
 use syntax::print::pprust;
 use syntax::ptr::P;
 use syntax::token::{self, Token, TokenKind, DelimToken};
 use syntax::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
 use syntax::sess::ParseSess;
-use syntax::source_map::respan;
 use syntax::struct_span_err;
 use syntax::util::comments::{doc_comment_style, strip_doc_comment_decoration};
+use syntax_pos::source_map::respan;
 use syntax_pos::symbol::{kw, sym, Symbol};
 use syntax_pos::{Span, BytePos, DUMMY_SP, FileName};
-use rustc_data_structures::thin_vec::ThinVec;
-use errors::{PResult, Applicability, DiagnosticBuilder, FatalError};
 use log::debug;
 
 use std::borrow::Cow;
index 59d7c2b423972c895d4fa1e70cf592286e472e7a..3777e17b5a15d95daa232c416cd844ebc773c446 100644 (file)
@@ -4,13 +4,12 @@
 
 use crate::{new_sub_parser_from_file, DirectoryOwnership};
 
+use rustc_errors::PResult;
 use syntax::attr;
 use syntax::ast::{self, Ident, Attribute, ItemKind, Mod, Crate};
 use syntax::token::{self, TokenKind};
-use syntax::source_map::{SourceMap, Span, DUMMY_SP, FileName};
-
+use syntax_pos::source_map::{SourceMap, Span, DUMMY_SP, FileName};
 use syntax_pos::symbol::sym;
-use errors::PResult;
 
 use std::path::{self, Path, PathBuf};
 
@@ -212,13 +211,13 @@ pub(super) fn default_submod_path(
         // `./<id>.rs` and `./<id>/mod.rs`.
         let relative_prefix_string;
         let relative_prefix = if let Some(ident) = relative {
-            relative_prefix_string = format!("{}{}", ident, path::MAIN_SEPARATOR);
+            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
             &relative_prefix_string
         } else {
             ""
         };
 
-        let mod_name = id.to_string();
+        let mod_name = id.name.to_string();
         let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
         let secondary_path_str = format!("{}{}{}mod.rs",
                                          relative_prefix, mod_name, path::MAIN_SEPARATOR);
index 1127c4b2d5f88c0bb65725f789db5ff1164d7ea7..42ece96adb99ab1dc8a261e89ec22b7ebb08a19a 100644 (file)
@@ -1,5 +1,6 @@
 use super::{Parser, PathStyle};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
+use rustc_errors::{PResult, Applicability, DiagnosticBuilder};
 use syntax::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac};
 use syntax::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind};
 use syntax::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor};
@@ -7,9 +8,8 @@
 use syntax::print::pprust;
 use syntax::ThinVec;
 use syntax::token;
-use syntax::source_map::{respan, Span, Spanned};
+use syntax_pos::source_map::{respan, Span, Spanned};
 use syntax_pos::symbol::{kw, sym};
-use errors::{PResult, Applicability, DiagnosticBuilder};
 
 type Expected = Option<&'static str>;
 
index 75bb67d47bc48cfc96044828e932866802387416..70c3458e7c0203095c5cb53249a94c741f95e56e 100644 (file)
@@ -1,16 +1,16 @@
 use super::{Parser, TokenType};
 use crate::maybe_whole;
+use rustc_errors::{PResult, Applicability, pluralize};
 use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs};
 use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
 use syntax::ast::MacArgs;
 use syntax::ThinVec;
 use syntax::token::{self, Token};
-use syntax::source_map::{Span, BytePos};
+use syntax_pos::source_map::{Span, BytePos};
 use syntax_pos::symbol::{kw, sym};
 
 use std::mem;
 use log::debug;
-use errors::{PResult, Applicability, pluralize};
 
 /// Specifies how to parse a path.
 #[derive(Copy, Clone, PartialEq)]
index b952e8814a361adec72a9e3fec9ad9b7dccd3d48..943b6ecc8255456feaa86f8f260608fc2d7a67f3 100644 (file)
@@ -6,6 +6,7 @@
 use crate::maybe_whole;
 use crate::DirectoryOwnership;
 
+use rustc_errors::{PResult, Applicability};
 use syntax::ThinVec;
 use syntax::ptr::P;
 use syntax::ast;
 use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac};
 use syntax::util::classify;
 use syntax::token;
-use syntax::source_map::{respan, Span};
-use syntax::symbol::{kw, sym};
+use syntax_pos::source_map::{respan, Span};
+use syntax_pos::symbol::{kw, sym};
 
 use std::mem;
-use errors::{PResult, Applicability};
 
 impl<'a> Parser<'a> {
     /// Parses a statement. This stops just before trailing semicolons on everything but items.
index 321427969051c54c24f464334a4d8235cd0a4039..84ffef68e9a661af0cbe72851c9d2118aadb5da9 100644 (file)
@@ -3,19 +3,17 @@
 
 use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
 
+use rustc_errors::{PResult, Applicability, pluralize};
+use rustc_error_codes::*;
 use syntax::ptr::P;
 use syntax::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident};
 use syntax::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
 use syntax::ast::{Mutability, AnonConst, Mac};
 use syntax::token::{self, Token};
-use syntax::source_map::Span;
 use syntax::struct_span_fatal;
+use syntax_pos::source_map::Span;
 use syntax_pos::symbol::kw;
 
-use errors::{PResult, Applicability, pluralize};
-
-use rustc_error_codes::*;
-
 /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
 /// `IDENT<<u8 as Trait>::AssocTy>`.
 ///
index 8601add3f6f9654d68b4591a640ff54794b7e963..97e9cb8dcdf6fc9bf339a513de5166c23001db59 100644 (file)
@@ -1,6 +1,6 @@
 //! Meta-syntax validation logic of attributes for post-expansion.
 
-use errors::{PResult, Applicability};
+use rustc_errors::{PResult, Applicability};
 use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
 use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind};
 use syntax::attr::mk_name_value_item_str;
index 4331d441aa0d24983f2db1bcff20750c1566eab2..32df6c4636c2d88338e4a791e0622f9de924d9af 100644 (file)
@@ -65,13 +65,13 @@ pub fn demand_eqtype_with_origin(&self,
         }
     }
 
-    pub fn demand_eqtype_pat(
+    pub fn demand_eqtype_pat_diag(
         &self,
         cause_span: Span,
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
         match_expr_span: Option<Span>,
-    ) {
+    ) -> Option<DiagnosticBuilder<'tcx>> {
         let cause = if let Some(span) = match_expr_span {
             self.cause(
                 cause_span,
@@ -80,9 +80,19 @@ pub fn demand_eqtype_pat(
         } else {
             self.misc(cause_span)
         };
-        self.demand_eqtype_with_origin(&cause, expected, actual).map(|mut err| err.emit());
+        self.demand_eqtype_with_origin(&cause, expected, actual)
     }
 
+    pub fn demand_eqtype_pat(
+        &self,
+        cause_span: Span,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+        match_expr_span: Option<Span>,
+    ) {
+        self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span)
+            .map(|mut err| err.emit());
+    }
 
     pub fn demand_coerce(&self,
                          expr: &hir::Expr,
index 4766360c048977dc4145700b409c478cfb0120c3..5bfc60c75406745e0c0a7ac2c2db42eca0599edf 100644 (file)
@@ -582,11 +582,21 @@ fn check_expr_break(
                 // If this is a break with a value, we need to type-check
                 // the expression. Get an expected type from the loop context.
                 let opt_coerce_to = {
+                    // We should release `enclosing_breakables` before the `check_expr_with_hint`
+                    // below, so can't move this block of code to the enclosing scope and share
+                    // `ctxt` with the second `encloding_breakables` borrow below.
                     let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-                    enclosing_breakables.find_breakable(target_id)
-                                        .coerce
-                                        .as_ref()
-                                        .map(|coerce| coerce.expected_ty())
+                    match enclosing_breakables.opt_find_breakable(target_id) {
+                        Some(ctxt) =>
+                            ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()),
+                        None => { // Avoid ICE when `break` is inside a closure (#65383).
+                            self.tcx.sess.delay_span_bug(
+                                expr.span,
+                                "break was outside loop, but no error was emitted",
+                            );
+                            return tcx.types.err;
+                        }
+                    }
                 };
 
                 // If the loop context is not a `loop { }`, then break with
index 9dd3bc624a51afc14cb320ab95144f4cc1fc26d4..71d1cd869a6a2df33e25deb6c199e4763699ff44 100644 (file)
@@ -703,7 +703,10 @@ fn check_pat_tuple_struct(
         let pat_ty = pat_ty.fn_sig(tcx).output();
         let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
 
-        self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span);
+        // Type-check the tuple struct pattern against the expected type.
+        let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, match_arm_pat_span);
+        let had_err = diag.is_some();
+        diag.map(|mut err| err.emit());
 
         // Type-check subpatterns.
         if subpats.len() == variant.fields.len()
@@ -721,7 +724,7 @@ fn check_pat_tuple_struct(
             }
         } else {
             // Pattern has wrong number of fields.
-            self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
+            self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
             on_error();
             return tcx.types.err;
         }
@@ -734,8 +737,9 @@ fn e0023(
         res: Res,
         qpath: &hir::QPath,
         subpats: &'tcx [P<Pat>],
-        fields: &[ty::FieldDef],
-        expected: Ty<'tcx>
+        fields: &'tcx [ty::FieldDef],
+        expected: Ty<'tcx>,
+        had_err: bool,
     ) {
         let subpats_ending = pluralize!(subpats.len());
         let fields_ending = pluralize!(fields.len());
@@ -763,9 +767,12 @@ fn e0023(
         // More generally, the expected type wants a tuple variant with one field of an
         // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
         // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
-        let missing_parenthesis = match expected.kind {
-            ty::Adt(_, substs) if fields.len() == 1 => {
-                let field_ty = fields[0].ty(self.tcx, substs);
+        let missing_parenthesis = match (&expected.kind, fields, had_err) {
+            // #67037: only do this if we could sucessfully type-check the expected type against
+            // the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
+            // `let P() = U;` where `P != U` with `struct P<T>(T);`.
+            (ty::Adt(_, substs), [field], false) => {
+                let field_ty = self.field_ty(pat_span, field, substs);
                 match field_ty.kind {
                     ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
                     _ => false,
index 2af66711d3cd0f271dffa717bc0594c9ddc1d567..c68e03be88c045fb2de599346b6c95c5bef278dd 100644 (file)
@@ -869,12 +869,18 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 
 impl fmt::Debug for Ident {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.is_raw_guess() {
+            write!(f, "r#")?;
+        }
         write!(f, "{}{:?}", self.name, self.span.ctxt())
     }
 }
 
 impl fmt::Display for Ident {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.is_raw_guess() {
+            write!(f, "r#")?;
+        }
         fmt::Display::fmt(&self.name, f)
     }
 }
index 1cb123e674c452c945f6f33a3685634334ddb6e0..6698e5d58be2f0ed97a7c05c013b1bbe4707f110 100644 (file)
@@ -658,46 +658,11 @@ public:
   }
 };
 
-class RustPrintModulePass : public ModulePass {
-  raw_ostream* OS;
-  DemangleFn Demangle;
-public:
-  static char ID;
-  RustPrintModulePass() : ModulePass(ID), OS(nullptr), Demangle(nullptr) {}
-  RustPrintModulePass(raw_ostream &OS, DemangleFn Demangle)
-      : ModulePass(ID), OS(&OS), Demangle(Demangle) {}
-
-  bool runOnModule(Module &M) override {
-    RustAssemblyAnnotationWriter AW(Demangle);
-
-    M.print(*OS, &AW, false);
-
-    return false;
-  }
-
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.setPreservesAll();
-  }
-
-  static StringRef name() { return "RustPrintModulePass"; }
-};
-
 } // namespace
 
-namespace llvm {
-  void initializeRustPrintModulePassPass(PassRegistry&);
-}
-
-char RustPrintModulePass::ID = 0;
-INITIALIZE_PASS(RustPrintModulePass, "print-rust-module",
-                "Print rust module to stderr", false, false)
-
 extern "C" LLVMRustResult
-LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M,
-                    const char *Path, DemangleFn Demangle) {
-  llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
+LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) {
   std::string ErrorInfo;
-
   std::error_code EC;
   raw_fd_ostream OS(Path, EC, sys::fs::F_None);
   if (EC)
@@ -707,11 +672,9 @@ LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M,
     return LLVMRustResult::Failure;
   }
 
+  RustAssemblyAnnotationWriter AAW(Demangle);
   formatted_raw_ostream FOS(OS);
-
-  PM->add(new RustPrintModulePass(FOS, Demangle));
-
-  PM->run(*unwrap(M));
+  unwrap(M)->print(FOS, &AAW);
 
   return LLVMRustResult::Success;
 }
index 627609c4a9c004320be4cfc131fef7e65e2475c1..3e39c8a7924467918d8b96c642199c002f5c61b1 100644 (file)
@@ -9,13 +9,21 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the fun
    |
 LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
    |        ^^
-   = note: ...so that the expression is assignable:
-           expected Type<'_>
-              found Type<'a>
+note: ...so that the expression is assignable
+  --> $DIR/project-fn-ret-invariant.rs:48:13
+   |
+LL |    bar(foo, x)
+   |             ^
+   = note: expected  `Type<'_>`
+              found  `Type<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
-   = note: ...so that the expression is assignable:
-           expected Type<'static>
-              found Type<'_>
+note: ...so that the expression is assignable
+  --> $DIR/project-fn-ret-invariant.rs:48:4
+   |
+LL |    bar(foo, x)
+   |    ^^^^^^^^^^^
+   = note: expected  `Type<'static>`
+              found  `Type<'_>`
 
 error: aborting due to previous error
 
index c80ed5ebf5cef6d0b1be235a624a71d98d0a99be..cd4cd8b198de8b4ee3ad4d8dc4864397589260d6 100644 (file)
@@ -49,9 +49,13 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th
    |
 LL |     let _ = ap.with_copy(|ap| { ap });
    |                          ^^^^^^^^^^^
-   = note: ...so that the expression is assignable:
-           expected core::ffi::VaList<'_, '_>
-              found core::ffi::VaList<'_, '_>
+note: ...so that the expression is assignable
+  --> $DIR/variadic-ffi-4.rs:16:33
+   |
+LL |     let _ = ap.with_copy(|ap| { ap });
+   |                                 ^^
+   = note: expected  `core::ffi::VaList<'_, '_>`
+              found  `core::ffi::VaList<'_, '_>`
 note: but, the lifetime must be valid for the method call at 16:13...
   --> $DIR/variadic-ffi-4.rs:16:13
    |
index 5e80c673258b8484432a74442ec7a58020d05ac9..3300293bb36caf2e8822d7b89b53f472c5b0cdd4 100644 (file)
@@ -9,13 +9,21 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the fun
    |
 LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
    |                          ^^
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<dyn std::fmt::Debug>
-              found std::boxed::Box<(dyn std::fmt::Debug + 'a)>
+note: ...so that the expression is assignable
+  --> $DIR/dyn-trait.rs:20:16
+   |
+LL |     static_val(x);
+   |                ^
+   = note: expected  `std::boxed::Box<dyn std::fmt::Debug>`
+              found  `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
    = note: but, the lifetime must be valid for the static lifetime...
-   = note: ...so that the types are compatible:
-           expected StaticTrait
-              found StaticTrait
+note: ...so that the types are compatible
+  --> $DIR/dyn-trait.rs:20:5
+   |
+LL |     static_val(x);
+   |     ^^^^^^^^^^
+   = note: expected  `StaticTrait`
+              found  `StaticTrait`
 
 error: aborting due to previous error
 
index b663e213ed05e357f8d8d48749573938828dd128..99700f2084e4a23aa6d159b7b1e83724dfcf2521 100644 (file)
@@ -21,9 +21,13 @@ note: but, the lifetime must be valid for the lifetime `'a` as defined on the tr
    |
 LL | trait T<'a> {
    |         ^^
-   = note: ...so that the types are compatible:
-           expected &'a Self
-              found &Self
+note: ...so that the types are compatible
+  --> $DIR/issue-16683.rs:4:14
+   |
+LL |         self.a();
+   |              ^
+   = note: expected  `&'a Self`
+              found  `&Self`
 
 error: aborting due to previous error
 
index adcbb62e3d5bda4ee80c04f2e5e0fbb9494c1511..adfc3f5085826b020f35e2bc688eec204833b4a3 100644 (file)
@@ -22,9 +22,13 @@ note: but, the lifetime must be valid for the lifetime `'a` as defined on the tr
    |
 LL | trait Foo<'a> {
    |           ^^
-   = note: ...so that the types are compatible:
-           expected &'a Self
-              found &Self
+note: ...so that the types are compatible
+  --> $DIR/issue-17758.rs:7:14
+   |
+LL |         self.foo();
+   |              ^^^
+   = note: expected  `&'a Self`
+              found  `&Self`
 
 error: aborting due to previous error
 
index 13c9c09461eae290e88fa5f3d56138e92346560b..c7fd134a129decdd7352545c9946fd7fedb4a70d 100644 (file)
@@ -88,9 +88,19 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on
    |
 LL | impl<'a> Publisher<'a> for MyStruct<'a> {
    |      ^^
-   = note: ...so that the types are compatible:
-           expected Publisher<'_>
-              found Publisher<'_>
+note: ...so that the types are compatible
+  --> $DIR/issue-20831-debruijn.rs:28:5
+   |
+LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+LL | |         // Not obvious, but there is an implicit lifetime here -------^
+LL | |
+LL | |
+...  |
+LL | |         self.sub = t;
+LL | |     }
+   | |_____^
+   = note: expected  `Publisher<'_>`
+              found  `Publisher<'_>`
 
 error: aborting due to 3 previous errors
 
index b79a5ddf3e1bf601ea4c96976270225b56aa8e78..a8960f7756367c6fecfa173ebec89a4ee5b2abc5 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the fun
    |
 LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
    |                       ^^
-   = note: ...so that the types are compatible:
-           expected (&&(T,),)
-              found (&&'a (T,),)
+note: ...so that the types are compatible
+  --> $DIR/issue-52213.rs:2:11
+   |
+LL |     match (&t,) {
+   |           ^^^^^
+   = note: expected  `(&&(T,),)`
+              found  `(&&'a (T,),)`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27...
   --> $DIR/issue-52213.rs:1:27
    |
index 7b910f5e3e5a654cc88ea4fa129185cfaa66cf4e..b8cafdc5c14b5e8a89a2bd6aab63f2a2a19aea0c 100644 (file)
@@ -15,9 +15,13 @@ note: ...so that the type `std::iter::Map<<Self as Graph<'a>>::EdgesIter, [closu
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>
-              found std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>
+note: ...so that the expression is assignable
+  --> $DIR/issue-55796.rs:16:9
+   |
+LL |         Box::new(self.out_edges(u).map(|e| e.target()))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+              found  `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/issue-55796.rs:21:9
@@ -36,9 +40,13 @@ note: ...so that the type `std::iter::Map<<Self as Graph<'a>>::EdgesIter, [closu
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>
-              found std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>
+note: ...so that the expression is assignable
+  --> $DIR/issue-55796.rs:21:9
+   |
+LL |         Box::new(self.in_edges(u).map(|e| e.target()))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+              found  `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.rs b/src/test/ui/issues/issue-65634-raw-ident-suggestion.rs
new file mode 100644 (file)
index 0000000..b928510
--- /dev/null
@@ -0,0 +1,22 @@
+#![allow(non_camel_case_types)]
+
+trait r#async {
+    fn r#struct(&self) {
+        println!("async");
+    }
+}
+
+trait r#await {
+    fn r#struct(&self) {
+        println!("await");
+    }
+}
+
+struct r#fn {}
+
+impl r#async for r#fn {}
+impl r#await for r#fn {}
+
+fn main() {
+    r#fn {}.r#struct(); //~ ERROR multiple applicable items in scope
+}
diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr
new file mode 100644 (file)
index 0000000..c7bb653
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:21:13
+   |
+LL |     r#fn {}.r#struct();
+   |             ^^^^^^^^ multiple `r#struct` found
+   |
+note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn`
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:4:5
+   |
+LL |     fn r#struct(&self) {
+   |     ^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `async::r#struct(r#fn {})` instead
+note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn`
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5
+   |
+LL |     fn r#struct(&self) {
+   |     ^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `await::r#struct(r#fn {})` instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0034`.
diff --git a/src/test/ui/issues/issue-66702-break-outside-loop-val.rs b/src/test/ui/issues/issue-66702-break-outside-loop-val.rs
new file mode 100644 (file)
index 0000000..bd3c00d
--- /dev/null
@@ -0,0 +1,7 @@
+// Breaks with values inside closures used to ICE (#66863)
+
+fn main() {
+    'some_label: loop {
+        || break 'some_label (); //~ ERROR: `break` inside of a closure
+    }
+}
diff --git a/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr b/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr
new file mode 100644 (file)
index 0000000..83bde97
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0267]: `break` inside of a closure
+  --> $DIR/issue-66702-break-outside-loop-val.rs:5:12
+   |
+LL |         || break 'some_label ();
+   |         -- ^^^^^^^^^^^^^^^^^^^^ cannot `break` inside of a closure
+   |         |
+   |         enclosing closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0267`.
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
new file mode 100644 (file)
index 0000000..44bd645
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for #67037.
+//
+// In type checking patterns, E0023 occurs when the tuple pattern and the expected
+// tuple pattern have different number of fields. For example, as below, `P()`,
+// the tuple struct pattern, has 0 fields, but requires 1 field.
+//
+// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
+// the scrutinee was of type `Some((a, b, c))`, and suggest that parenthesis be added.
+//
+// However, we did not account for the expected type being different than the tuple pattern type.
+// This caused an issue when the tuple pattern type (`P<T>`) was generic.
+// Specifically, we tried deriving the 0th field's type using the `substs` of the expected type.
+// When attempting to substitute `T`, there was no such substitution, so "out of range" occured.
+
+struct U {} // 0 type parameters offered
+struct P<T>(T); // 1 type parameter wanted
+
+fn main() {
+    let P() = U {}; //~ ERROR mismatched types
+    //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 1 field
+}
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
new file mode 100644 (file)
index 0000000..521dd02
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+   |
+LL |     let P() = U {};
+   |         ^^^ expected struct `U`, found struct `P`
+   |
+   = note: expected struct `U`
+              found struct `P<_>`
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 1 field
+  --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+   |
+LL | struct P<T>(T); // 1 type parameter wanted
+   | --------------- tuple struct defined here
+...
+LL |     let P() = U {};
+   |         ^^^ expected 1 field, found 0
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0023, E0308.
+For more information about an error, try `rustc --explain E0023`.
index 714a63b670c66a96688a0cbeb14c71d670aa181d..69a6ab004fd915ae014acfc5c238a9b124e9a079 100644 (file)
@@ -21,9 +21,13 @@ note: but, the lifetime must be valid for the lifetime `'_` as defined on the im
    |
 LL | impl Foo<'_> {
    |          ^^
-   = note: ...so that the expression is assignable:
-           expected Foo<'_>
-              found Foo<'_>
+note: ...so that the expression is assignable
+  --> $DIR/issue-55394.rs:9:9
+   |
+LL |         Foo { bar }
+   |         ^^^^^^^^^^^
+   = note: expected  `Foo<'_>`
+              found  `Foo<'_>`
 
 error: aborting due to previous error
 
index 3a152fbc6fce8e5898ac1261ca1080b80497e3cd..58f206742f4f57b71192cf9742d22d9a78e852ac 100644 (file)
@@ -14,9 +14,13 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    |                  ^^
-   = note: ...so that the types are compatible:
-           expected Visitor<'d>
-              found Visitor<'_>
+note: ...so that the types are compatible
+  --> $DIR/normalization-bounds-error.rs:12:1
+   |
+LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `Visitor<'d>`
+              found  `Visitor<'_>`
 
 error: aborting due to previous error
 
index 6986389af88149ee503d183507fb1ee1fa807319..5191deca281ccea48c667a48ef0fff5475b84c94 100644 (file)
@@ -11,17 +11,25 @@ LL | /     fn from_box(b: Box<B>) -> Self {
 LL | |         C { f: b }
 LL | |     }
    | |_____^
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<std::boxed::Box<&isize>>
-              found std::boxed::Box<std::boxed::Box<&isize>>
+note: ...so that the expression is assignable
+  --> $DIR/type-alias-free-regions.rs:17:16
+   |
+LL |         C { f: b }
+   |                ^
+   = note: expected  `std::boxed::Box<std::boxed::Box<&isize>>`
+              found  `std::boxed::Box<std::boxed::Box<&isize>>`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
   --> $DIR/type-alias-free-regions.rs:15:6
    |
 LL | impl<'a> FromBox<'a> for C<'a> {
    |      ^^
-   = note: ...so that the expression is assignable:
-           expected C<'a>
-              found C<'_>
+note: ...so that the expression is assignable
+  --> $DIR/type-alias-free-regions.rs:17:9
+   |
+LL |         C { f: b }
+   |         ^^^^^^^^^^
+   = note: expected  `C<'a>`
+              found  `C<'_>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/type-alias-free-regions.rs:27:16
@@ -36,17 +44,25 @@ LL | /     fn from_tuple(b: (B,)) -> Self {
 LL | |         C { f: Box::new(b.0) }
 LL | |     }
    | |_____^
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<&isize>
-              found std::boxed::Box<&isize>
+note: ...so that the expression is assignable
+  --> $DIR/type-alias-free-regions.rs:27:25
+   |
+LL |         C { f: Box::new(b.0) }
+   |                         ^^^
+   = note: expected  `std::boxed::Box<&isize>`
+              found  `std::boxed::Box<&isize>`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6...
   --> $DIR/type-alias-free-regions.rs:25:6
    |
 LL | impl<'a> FromTuple<'a> for C<'a> {
    |      ^^
-   = note: ...so that the expression is assignable:
-           expected C<'a>
-              found C<'_>
+note: ...so that the expression is assignable
+  --> $DIR/type-alias-free-regions.rs:27:9
+   |
+LL |         C { f: Box::new(b.0) }
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `C<'a>`
+              found  `C<'_>`
 
 error: aborting due to 2 previous errors
 
index 4ebd991078864f6cb986739c477de2d5dc6744e5..37be450fd0a791aedab7a58226feefb4c3d1827c 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the fun
    |
 LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
    |        ^^
-   = note: ...so that the types are compatible:
-           expected Foo<'_>
-              found Foo<'a>
+note: ...so that the types are compatible
+  --> $DIR/constant-in-expr-inherent-1.rs:8:5
+   |
+LL |     <Foo<'a>>::C
+   |     ^^^^^^^^^^^^
+   = note: expected  `Foo<'_>`
+              found  `Foo<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that reference does not outlive borrowed content
   --> $DIR/constant-in-expr-inherent-1.rs:8:5
index d61659e7e9afcd3c046fb42cad71504156ef8d2e..4ee32847c5ec8555771612d5f29545ef8b7bfa78 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the fun
    |
 LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
    |        ^^
-   = note: ...so that the types are compatible:
-           expected Foo<'_>
-              found Foo<'a>
+note: ...so that the types are compatible
+  --> $DIR/constant-in-expr-trait-item-3.rs:10:5
+   |
+LL |     T::C
+   |     ^^^^
+   = note: expected  `Foo<'_>`
+              found  `Foo<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that reference does not outlive borrowed content
   --> $DIR/constant-in-expr-trait-item-3.rs:10:5
index d66322c48ec98c3f304e7a31574df4e90c858589..1952ee8269d5b1a912d005b8c5170287d3723ef4 100644 (file)
@@ -19,9 +19,13 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
    |             ^^
-   = note: ...so that the expression is assignable:
-           expected &'b (dyn SomeTrait + 'b)
-              found &dyn SomeTrait
+note: ...so that the expression is assignable
+  --> $DIR/object-lifetime-default-elision.rs:71:5
+   |
+LL |     ss
+   |     ^^
+   = note: expected  `&'b (dyn SomeTrait + 'b)`
+              found  `&dyn SomeTrait`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/object-lifetime-default-elision.rs:71:5
@@ -44,9 +48,13 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
    |             ^^
-   = note: ...so that the expression is assignable:
-           expected &'b (dyn SomeTrait + 'b)
-              found &dyn SomeTrait
+note: ...so that the expression is assignable
+  --> $DIR/object-lifetime-default-elision.rs:71:5
+   |
+LL |     ss
+   |     ^^
+   = note: expected  `&'b (dyn SomeTrait + 'b)`
+              found  `&dyn SomeTrait`
 
 error: aborting due to 2 previous errors
 
index bf9cbcdab2e89b58f2348eaed9894c6286e61c30..a986980fab97b1d742ef74851ea10dc8234fd12c 100644 (file)
@@ -11,11 +11,11 @@ fn test_union() {
 }
 
 fn test_if_2() {
-    let _ = r#if; //~ ERROR cannot find value `if` in this scope
+    let _ = r#if; //~ ERROR cannot find value `r#if` in this scope
 }
 
 fn test_struct_2() {
-    let _ = r#struct; //~ ERROR cannot find value `struct` in this scope
+    let _ = r#struct; //~ ERROR cannot find value `r#struct` in this scope
 }
 
 fn test_union_2() {
index fd8eda3770d27fb01c679b06504a4069ad9ea543..f7b6c894a90fea2ade2bd5a9692ed5cf4cf1b66f 100644 (file)
@@ -16,13 +16,13 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
 LL |     r#union Test;
    |             ^^^^ expected one of 8 possible tokens
 
-error[E0425]: cannot find value `if` in this scope
+error[E0425]: cannot find value `r#if` in this scope
   --> $DIR/raw-literal-keywords.rs:14:13
    |
 LL |     let _ = r#if;
    |             ^^^^ not found in this scope
 
-error[E0425]: cannot find value `struct` in this scope
+error[E0425]: cannot find value `r#struct` in this scope
   --> $DIR/raw-literal-keywords.rs:18:13
    |
 LL |     let _ = r#struct;
index 14934d6fa4899c9490be3bc91282204fe33222d2..e889651647034ec245574e92fda12d8792b16d8f 100644 (file)
@@ -34,17 +34,25 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the fun
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |      ^^
-   = note: ...so that the expression is assignable:
-           expected &[u8]
-              found &'a [u8]
+note: ...so that the expression is assignable
+  --> $DIR/region-object-lifetime-in-coercion.rs:26:14
+   |
+LL |     Box::new(v)
+   |              ^
+   = note: expected  `&[u8]`
+              found  `&'a [u8]`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9...
   --> $DIR/region-object-lifetime-in-coercion.rs:25:9
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |         ^^
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<(dyn Foo + 'b)>
-              found std::boxed::Box<dyn Foo>
+note: ...so that the expression is assignable
+  --> $DIR/region-object-lifetime-in-coercion.rs:26:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^
+   = note: expected  `std::boxed::Box<(dyn Foo + 'b)>`
+              found  `std::boxed::Box<dyn Foo>`
 
 error: aborting due to 4 previous errors
 
index a636c9ef22c83ead07a67223d423f9f6e9347ddb..865e967fba32e963b3e0dbdb3007de5a3f67e36a 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the imp
    |
 LL | impl<'a> Foo<'static> for &'a i32 {
    |      ^^
-   = note: ...so that the types are compatible:
-           expected Foo<'static>
-              found Foo<'static>
+note: ...so that the types are compatible
+  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
+   |
+LL | impl<'a> Foo<'static> for &'a i32 {
+   |          ^^^^^^^^^^^^
+   = note: expected  `Foo<'static>`
+              found  `Foo<'static>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the type `&i32` will meet its required lifetime bounds
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
@@ -30,9 +34,13 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the imp
    |
 LL | impl<'a,'b> Foo<'b> for &'a i64 {
    |      ^^
-   = note: ...so that the types are compatible:
-           expected Foo<'b>
-              found Foo<'_>
+note: ...so that the types are compatible
+  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:13
+   |
+LL | impl<'a,'b> Foo<'b> for &'a i64 {
+   |             ^^^^^^^
+   = note: expected  `Foo<'b>`
+              found  `Foo<'_>`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9...
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9
    |
index 81256e3b46cbb94a399d27175f88cd9614994b28..6a34871c07efdfdfeb8075d6dcb3f856ee2a3f1f 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the imp
    |
 LL | impl<'a> Foo for &'a i32 {
    |      ^^
-   = note: ...so that the types are compatible:
-           expected Foo
-              found Foo
+note: ...so that the types are compatible
+  --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
+   |
+LL | impl<'a> Foo for &'a i32 {
+   |          ^^^
+   = note: expected  `Foo`
+              found  `Foo`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the type `&i32` will meet its required lifetime bounds
   --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
index 8e473dad69341e3375c6018311982e5f700032f6..28873ab807f8d7bcff4eb1068232875e7384a14b 100644 (file)
@@ -15,9 +15,13 @@ note: ...so that the type `(dyn A<T> + 'a)` is not borrowed for too long
 LL |     box B(&*v) as Box<dyn X>
    |           ^^^
    = note: but, the lifetime must be valid for the static lifetime...
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<(dyn X + 'static)>
-              found std::boxed::Box<dyn X>
+note: ...so that the expression is assignable
+  --> $DIR/regions-close-object-into-object-2.rs:10:5
+   |
+LL |     box B(&*v) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `std::boxed::Box<(dyn X + 'static)>`
+              found  `std::boxed::Box<dyn X>`
 
 error: aborting due to previous error
 
index c80d13e15b14726c16bc6e38b120e550220aea4b..449a5b5fdd4d654c69ebcd8e2314284674ce09fa 100644 (file)
@@ -15,9 +15,13 @@ note: ...so that the type `(dyn A<U> + 'a)` is not borrowed for too long
 LL |     box B(&*v) as Box<dyn X>
    |           ^^^
    = note: but, the lifetime must be valid for the static lifetime...
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<(dyn X + 'static)>
-              found std::boxed::Box<dyn X>
+note: ...so that the expression is assignable
+  --> $DIR/regions-close-object-into-object-4.rs:10:5
+   |
+LL |     box B(&*v) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `std::boxed::Box<(dyn X + 'static)>`
+              found  `std::boxed::Box<dyn X>`
 
 error: aborting due to previous error
 
index ef21316ea83aea639866521ca102079714d32282..b2a7afaf1b452ff3f37257a031dd4a81b5ff6df2 100644 (file)
@@ -19,9 +19,13 @@ note: but, the lifetime must be valid for the lifetime `'c` as defined on the fu
    |
 LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
    |                          ^^
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<(dyn SomeTrait + 'c)>
-              found std::boxed::Box<dyn SomeTrait>
+note: ...so that the expression is assignable
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
+   |
+LL |     box v as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `std::boxed::Box<(dyn SomeTrait + 'c)>`
+              found  `std::boxed::Box<dyn SomeTrait>`
 
 error: aborting due to previous error
 
index 12b89787d5f18ff5cfbf5aa83c3c4d2a8004ec9b..58f74e4ee142d67f412634030199e04cc90ba3d6 100644 (file)
@@ -9,17 +9,25 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the fun
    |
 LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
    |                ^^
-   = note: ...so that the expression is assignable:
-           expected &Ast<'_>
-              found &Ast<'a>
+note: ...so that the expression is assignable
+  --> $DIR/regions-creating-enums4.rs:7:14
+   |
+LL |     Ast::Add(x, y)
+   |              ^
+   = note: expected  `&Ast<'_>`
+              found  `&Ast<'a>`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19...
   --> $DIR/regions-creating-enums4.rs:6:19
    |
 LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
    |                   ^^
-   = note: ...so that the expression is assignable:
-           expected Ast<'b>
-              found Ast<'_>
+note: ...so that the expression is assignable
+  --> $DIR/regions-creating-enums4.rs:7:5
+   |
+LL |     Ast::Add(x, y)
+   |     ^^^^^^^^^^^^^^
+   = note: expected  `Ast<'b>`
+              found  `Ast<'_>`
 
 error: aborting due to previous error
 
index b93dd0d4c57c9e06785409bd9e8e4adf359ca715..ffc2a259485aa77afb467fbc07a36520a7836553 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th
    |
 LL |     s.f(|p| p)
    |         ^^^^^
-   = note: ...so that the expression is assignable:
-           expected &i32
-              found &i32
+note: ...so that the expression is assignable
+  --> $DIR/regions-escape-method.rs:15:13
+   |
+LL |     s.f(|p| p)
+   |             ^
+   = note: expected  `&i32`
+              found  `&i32`
 note: but, the lifetime must be valid for the method call at 15:5...
   --> $DIR/regions-escape-method.rs:15:5
    |
index a6b165e2d444474e563ff45d1f7b5a95e3320295..90823464c56d26ee8fef1219cda652aa071a9c33 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th
    |
 LL |     with(|o| o)
    |          ^^^^^
-   = note: ...so that the expression is assignable:
-           expected &isize
-              found &isize
+note: ...so that the expression is assignable
+  --> $DIR/regions-escape-via-trait-or-not.rs:18:14
+   |
+LL |     with(|o| o)
+   |              ^
+   = note: expected  `&isize`
+              found  `&isize`
 note: but, the lifetime must be valid for the expression at 18:5...
   --> $DIR/regions-escape-via-trait-or-not.rs:18:5
    |
index f4eb5c8644f034872c80dba20474d346bbfbc90e..8fce1609d78305d64d441dac01685f33e7b1dfeb 100644 (file)
@@ -29,9 +29,18 @@ LL | |         if false { return ay; }
 LL | |         return z;
 LL | |     }));
    | |_____^
-   = note: ...so that the types are compatible:
-           expected &isize
-              found &isize
+note: ...so that the types are compatible
+  --> $DIR/regions-nested-fns.rs:13:76
+   |
+LL |       ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+   |  ____________________________________________________________________________^
+LL | |         if false { return x; }
+LL | |         if false { return ay; }
+LL | |         return z;
+LL | |     }));
+   | |_____^
+   = note: expected  `&isize`
+              found  `&isize`
 
 error[E0312]: lifetime of reference outlives lifetime of borrowed content...
   --> $DIR/regions-nested-fns.rs:14:27
index d29fd80943f73a2030b1695284f100a793568f36..8a600d2a1e6955166e78ccdf17a3f424abbf2790 100644 (file)
@@ -17,9 +17,16 @@ note: ...but the lifetime must also be valid for the lifetime `'b` as defined on
    |
 LL | fn bar<'a, 'b>()
    |            ^^
-   = note: ...so that the types are compatible:
-           expected Project<'a, 'b>
-              found Project<'_, '_>
+note: ...so that the types are compatible
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+   |
+LL | / fn bar<'a, 'b>()
+LL | |     where <() as Project<'a, 'b>>::Item : Eq
+LL | | {
+LL | | }
+   | |_^
+   = note: expected  `Project<'a, 'b>`
+              found  `Project<'_, '_>`
 
 error: aborting due to previous error
 
index 49076673ad3989dd1f58ccbe183dcdf592d1c20a..2895a0ccdeec8f40d10768028000e9addcedc807 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th
    |
 LL |     with(|o| o)
    |          ^^^^^
-   = note: ...so that the expression is assignable:
-           expected &isize
-              found &isize
+note: ...so that the expression is assignable
+  --> $DIR/regions-ret-borrowed-1.rs:10:14
+   |
+LL |     with(|o| o)
+   |              ^
+   = note: expected  `&isize`
+              found  `&isize`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14...
   --> $DIR/regions-ret-borrowed-1.rs:9:14
    |
index eb1ade27acea7a3f8c51e31959a43ceca7da3fce..b74f10f5075ebdf2db4f45e518eef0435f6fb853 100644 (file)
@@ -9,9 +9,13 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th
    |
 LL |     with(|o| o)
    |          ^^^^^
-   = note: ...so that the expression is assignable:
-           expected &isize
-              found &isize
+note: ...so that the expression is assignable
+  --> $DIR/regions-ret-borrowed.rs:13:14
+   |
+LL |     with(|o| o)
+   |              ^
+   = note: expected  `&isize`
+              found  `&isize`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14...
   --> $DIR/regions-ret-borrowed.rs:12:14
    |
index ef69f2535dc1ee0deab609d22fb1472d43a3ad60..58b79d212700cfd81c385af01abe8f297705ca89 100644 (file)
@@ -36,9 +36,13 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
    |
 LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
    |            ^^
-   = note: ...so that the expression is assignable:
-           expected &'b mut (dyn Dummy + 'b)
-              found &mut (dyn Dummy + 'b)
+note: ...so that the expression is assignable
+  --> $DIR/regions-trait-object-subtyping.rs:15:5
+   |
+LL |     x
+   |     ^
+   = note: expected  `&'b mut (dyn Dummy + 'b)`
+              found  `&mut (dyn Dummy + 'b)`
 
 error[E0308]: mismatched types
   --> $DIR/regions-trait-object-subtyping.rs:22:5
index e55f0232ff94b923ec2b998d56a34323b51e268e..527babb01208f3a6003060689c284db4dab0d34c 100644 (file)
@@ -105,9 +105,13 @@ note: ...but the lifetime must also be valid for the lifetime `'l2` as defined o
    |
 LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
    |               ^^^
-   = note: ...so that the types are compatible:
-           expected W<'l1, 'l2>
-              found W<'_, '_>
+note: ...so that the types are compatible
+  --> $DIR/reject-specialized-drops-8142.rs:54:1
+   |
+LL | impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJECT
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `W<'l1, 'l2>`
+              found  `W<'_, '_>`
 
 error: aborting due to 8 previous errors
 
index 6c01383d9610d07fb5d4b3faf39b681be6911b38..0a8073c0be2ea627cdd59d843d88af9fc9f02db1 100644 (file)
@@ -5,5 +5,5 @@ pub fn break() {} //~ ERROR expected identifier, found keyword `break`
 
 fn main() {
     foo::let(); //~ ERROR expected identifier, found keyword `let`
-    r#break(); //~ ERROR cannot find function `break` in this scope
+    r#break(); //~ ERROR cannot find function `r#break` in this scope
 }
index 58eb87c00a4112d5e8c94eddcadca2cd05abce69..62b76318e09b5424f1ebab7a3c03c2c55a720237 100644 (file)
@@ -20,7 +20,7 @@ help: you can escape reserved keywords to use them as identifiers
 LL |     foo::r#let();
    |          ^^^^^
 
-error[E0425]: cannot find function `break` in this scope
+error[E0425]: cannot find function `r#break` in this scope
   --> $DIR/raw-name-use-suggestion.rs:8:5
    |
 LL |     r#break();
index 88c9c473eb0c7c0c53b32a5d83e7917ab0a54935..9fdcd4de495c017c0d026d77acf56c8210184fa1 100644 (file)
@@ -14,9 +14,13 @@ note: ...but the lifetime must also be valid for the lifetime `'b` as defined on
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |         ^^
-   = note: ...so that the types are compatible:
-           expected T1<'a>
-              found T1<'_>
+note: ...so that the types are compatible
+  --> $DIR/trait-impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:13
+   |
+LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
+   |             ^^^^^^^^^^
+   = note: expected  `T1<'a>`
+              found  `T1<'_>`
 
 error: aborting due to previous error
 
index d0475bf08c38d2bb8fe602ac25f40ae2e1af2b4b..e6029e0d4623ae73523bb6f763a8484345980de2 100644 (file)
@@ -18,9 +18,13 @@ note: ...so that reference does not outlive borrowed content
 LL |     Box::new(items.iter())
    |              ^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
-   = note: ...so that the expression is assignable:
-           expected std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>
-              found std::boxed::Box<dyn std::iter::Iterator<Item = &T>>
+note: ...so that the expression is assignable
+  --> $DIR/dyn-trait-underscore.rs:8:5
+   |
+LL |     Box::new(items.iter())
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
+              found  `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
 
 error: aborting due to previous error