about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-06-21 22:32:35 -0400
committerAaron Hill <aa1ronham@gmail.com>2020-06-22 14:35:42 -0400
commit3ed96a6d638f8dc8aa081ca1ad82e61caa8930ca (patch)
treec9e61e21031dd995975cb1fe073ab7bf0cc8ba01
parent1a4e2b6f9c75a0e21722c88a0e3b610d6ffc3ae3 (diff)
downloadrust-3ed96a6d638f8dc8aa081ca1ad82e61caa8930ca.tar.gz
rust-3ed96a6d638f8dc8aa081ca1ad82e61caa8930ca.zip
Point at the call spawn when overflow occurs during monomorphization
This improves the output for issue #72577, but there's still more work
to be done.

Currently, an overflow error during monomorphization results in an error
that points at the function we were unable to monomorphize. However, we
don't point at the call that caused the monomorphization to happen. In
the overflow occurs in a large recursive function, it may be difficult
to determine where the issue is.

This commit tracks and `Span` information during collection of
`MonoItem`s, which is used when emitting an overflow error. `MonoItem`
itself is unchanged, so this only affects
`src/librustc_mir/monomorphize/collector.rs`
-rw-r--r--src/librustc_mir/monomorphize/collector.rs137
-rw-r--r--src/test/ui/infinite/infinite-instantiation.rs10
-rw-r--r--src/test/ui/infinite/infinite-instantiation.stderr11
-rw-r--r--src/test/ui/issues/issue-67552.rs2
-rw-r--r--src/test/ui/issues/issue-67552.stderr8
-rw-r--r--src/test/ui/issues/issue-8727.rs6
-rw-r--r--src/test/ui/issues/issue-8727.stderr6
-rw-r--r--src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr18
-rw-r--r--src/test/ui/recursion/recursion.rs5
-rw-r--r--src/test/ui/recursion/recursion.stderr9
10 files changed, 132 insertions, 80 deletions
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 36f3947d830..84ef040741a 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -178,7 +178,7 @@ use crate::monomorphize;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
-use rustc_errors::ErrorReported;
+use rustc_errors::{ErrorReported, FatalError};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
@@ -195,6 +195,7 @@ use rustc_middle::ty::print::obsolete::DefPathBasedNames;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_session::config::EntryFnType;
+use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
 use smallvec::SmallVec;
 use std::iter;
 
@@ -294,7 +295,13 @@ pub fn collect_crate_mono_items(
         tcx.sess.time("monomorphization_collector_graph_walk", || {
             par_iter(roots).for_each(|root| {
                 let mut recursion_depths = DefIdMap::default();
-                collect_items_rec(tcx, root, visited, &mut recursion_depths, inlining_map);
+                collect_items_rec(
+                    tcx,
+                    dummy_spanned(root),
+                    visited,
+                    &mut recursion_depths,
+                    inlining_map,
+                );
             });
         });
     }
@@ -323,29 +330,30 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
     // We can only codegen items that are instantiable - items all of
     // whose predicates hold. Luckily, items that aren't instantiable
     // can't actually be used, so we can just skip codegenning them.
-    roots.retain(|root| root.is_instantiable(tcx));
-
     roots
+        .into_iter()
+        .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node))
+        .collect()
 }
 
 // Collect all monomorphized items reachable from `starting_point`
 fn collect_items_rec<'tcx>(
     tcx: TyCtxt<'tcx>,
-    starting_point: MonoItem<'tcx>,
+    starting_point: Spanned<MonoItem<'tcx>>,
     visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
     recursion_depths: &mut DefIdMap<usize>,
     inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
 ) {
-    if !visited.lock_mut().insert(starting_point) {
+    if !visited.lock_mut().insert(starting_point.node) {
         // We've been here already, no need to search again.
         return;
     }
-    debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx, true));
+    debug!("BEGIN collect_items_rec({})", starting_point.node.to_string(tcx, true));
 
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
 
-    match starting_point {
+    match starting_point.node {
         MonoItem::Static(def_id) => {
             let instance = Instance::mono(tcx, def_id);
 
@@ -353,7 +361,7 @@ fn collect_items_rec<'tcx>(
             debug_assert!(should_monomorphize_locally(tcx, &instance));
 
             let ty = instance.monomorphic_ty(tcx);
-            visit_drop_use(tcx, ty, true, &mut neighbors);
+            visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors);
 
             recursion_depth_reset = None;
 
@@ -366,7 +374,8 @@ fn collect_items_rec<'tcx>(
             debug_assert!(should_monomorphize_locally(tcx, &instance));
 
             // Keep track of the monomorphization recursion depth
-            recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths));
+            recursion_depth_reset =
+                Some(check_recursion_limit(tcx, instance, starting_point.span, recursion_depths));
             check_type_length_limit(tcx, instance);
 
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
@@ -378,7 +387,7 @@ fn collect_items_rec<'tcx>(
         }
     }
 
-    record_accesses(tcx, starting_point, &neighbors[..], inlining_map);
+    record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
 
     for neighbour in neighbors {
         collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map);
@@ -388,13 +397,13 @@ fn collect_items_rec<'tcx>(
         recursion_depths.insert(def_id, depth);
     }
 
-    debug!("END collect_items_rec({})", starting_point.to_string(tcx, true));
+    debug!("END collect_items_rec({})", starting_point.node.to_string(tcx, true));
 }
 
-fn record_accesses<'tcx>(
+fn record_accesses<'a, 'tcx: 'a>(
     tcx: TyCtxt<'tcx>,
     caller: MonoItem<'tcx>,
-    callees: &[MonoItem<'tcx>],
+    callees: impl Iterator<Item = &'a MonoItem<'tcx>>,
     inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
 ) {
     let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| {
@@ -405,7 +414,7 @@ fn record_accesses<'tcx>(
     // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec`
     // instead to avoid creating this `SmallVec`.
     let accesses: SmallVec<[_; 128]> =
-        callees.iter().map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
+        callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
 
     inlining_map.lock_mut().record_accesses(caller, &accesses);
 }
@@ -413,6 +422,7 @@ fn record_accesses<'tcx>(
 fn check_recursion_limit<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
+    span: Span,
     recursion_depths: &mut DefIdMap<usize>,
 ) -> (DefId, usize) {
     let def_id = instance.def_id();
@@ -432,12 +442,13 @@ fn check_recursion_limit<'tcx>(
     // infinite expansion.
     if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
         let error = format!("reached the recursion limit while instantiating `{}`", instance);
-        if let Some(def_id) = def_id.as_local() {
-            let hir_id = tcx.hir().as_local_hir_id(def_id);
-            tcx.sess.span_fatal(tcx.hir().span(hir_id), &error);
-        } else {
-            tcx.sess.fatal(&error);
-        }
+        let mut err = tcx.sess.struct_span_fatal(span, &error);
+        err.span_note(
+            tcx.def_span(def_id),
+            &format!("`{}` defined here", tcx.def_path_str(def_id)),
+        );
+        err.emit();
+        FatalError.raise();
     }
 
     recursion_depths.insert(def_id, recursion_depth + 1);
@@ -498,7 +509,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
 struct MirNeighborCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
-    output: &'a mut Vec<MonoItem<'tcx>>,
+    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
     instance: Instance<'tcx>,
 }
 
@@ -520,6 +531,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
         debug!("visiting rvalue {:?}", *rvalue);
 
+        let span = self.body.source_info(location).span;
+
         match *rvalue {
             // When doing an cast from a regular pointer to a fat pointer, we
             // have to instantiate all methods of the trait being cast to, so we
@@ -542,6 +555,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                         self.tcx,
                         target_ty,
                         source_ty,
+                        span,
                         self.output,
                     );
                 }
@@ -553,7 +567,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             ) => {
                 let fn_ty = operand.ty(self.body, self.tcx);
                 let fn_ty = self.monomorphize(fn_ty);
-                visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+                visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output);
             }
             mir::Rvalue::Cast(
                 mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
@@ -571,7 +585,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                             ty::ClosureKind::FnOnce,
                         );
                         if should_monomorphize_locally(self.tcx, &instance) {
-                            self.output.push(create_fn_mono_item(instance));
+                            self.output.push(create_fn_mono_item(instance, span));
                         }
                     }
                     _ => bug!(),
@@ -583,7 +597,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     tcx.require_lang_item(ExchangeMallocFnLangItem, None);
                 let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
                 if should_monomorphize_locally(tcx, &instance) {
-                    self.output.push(create_fn_mono_item(instance));
+                    self.output.push(create_fn_mono_item(instance, span));
                 }
             }
             mir::Rvalue::ThreadLocalRef(def_id) => {
@@ -591,7 +605,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                 let instance = Instance::mono(self.tcx, def_id);
                 if should_monomorphize_locally(self.tcx, &instance) {
                     trace!("collecting thread-local static {:?}", def_id);
-                    self.output.push(MonoItem::Static(def_id));
+                    self.output.push(respan(span, MonoItem::Static(def_id)));
                 }
             }
             _ => { /* not interesting */ }
@@ -626,32 +640,33 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
     fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
         debug!("visiting terminator {:?} @ {:?}", terminator, location);
+        let source = self.body.source_info(location).span;
 
         let tcx = self.tcx;
         match terminator.kind {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.body, tcx);
                 let callee_ty = self.monomorphize(callee_ty);
-                visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
+                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output);
             }
             mir::TerminatorKind::Drop { ref place, .. }
             | mir::TerminatorKind::DropAndReplace { ref place, .. } => {
                 let ty = place.ty(self.body, self.tcx).ty;
                 let ty = self.monomorphize(ty);
-                visit_drop_use(self.tcx, ty, true, self.output);
+                visit_drop_use(self.tcx, ty, true, source, self.output);
             }
             mir::TerminatorKind::InlineAsm { ref operands, .. } => {
                 for op in operands {
                     match *op {
                         mir::InlineAsmOperand::SymFn { ref value } => {
                             let fn_ty = self.monomorphize(value.literal.ty);
-                            visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+                            visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output);
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
                             if should_monomorphize_locally(self.tcx, &instance) {
                                 trace!("collecting asm sym static {:?}", def_id);
-                                self.output.push(MonoItem::Static(def_id));
+                                self.output.push(respan(source, MonoItem::Static(def_id)));
                             }
                         }
                         _ => {}
@@ -687,17 +702,19 @@ fn visit_drop_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     let instance = Instance::resolve_drop_in_place(tcx, ty);
-    visit_instance_use(tcx, instance, is_direct_call, output);
+    visit_instance_use(tcx, instance, is_direct_call, source, output);
 }
 
 fn visit_fn_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     if let ty::FnDef(def_id, substs) = ty.kind {
         let instance = if is_direct_call {
@@ -706,7 +723,7 @@ fn visit_fn_use<'tcx>(
             ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs)
                 .unwrap()
         };
-        visit_instance_use(tcx, instance, is_direct_call, output);
+        visit_instance_use(tcx, instance, is_direct_call, source, output);
     }
 }
 
@@ -714,7 +731,8 @@ fn visit_instance_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::Instance<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
     if !should_monomorphize_locally(tcx, &instance) {
@@ -730,7 +748,7 @@ fn visit_instance_use<'tcx>(
         ty::InstanceDef::DropGlue(_, None) => {
             // Don't need to emit noop drop glue if we are calling directly.
             if !is_direct_call {
-                output.push(create_fn_mono_item(instance));
+                output.push(create_fn_mono_item(instance, source));
             }
         }
         ty::InstanceDef::DropGlue(_, Some(_))
@@ -740,7 +758,7 @@ fn visit_instance_use<'tcx>(
         | ty::InstanceDef::Item(..)
         | ty::InstanceDef::FnPtrShim(..)
         | ty::InstanceDef::CloneShim(..) => {
-            output.push(create_fn_mono_item(instance));
+            output.push(create_fn_mono_item(instance, source));
         }
     }
 }
@@ -832,7 +850,6 @@ fn find_vtable_types_for_unsizing<'tcx>(
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
         let param_env = ty::ParamEnv::reveal_all();
         let type_has_metadata = |ty: Ty<'tcx>| -> bool {
-            use rustc_span::DUMMY_SP;
             if ty.is_sized(tcx.at(DUMMY_SP), param_env) {
                 return false;
             }
@@ -886,9 +903,9 @@ fn find_vtable_types_for_unsizing<'tcx>(
     }
 }
 
-fn create_fn_mono_item(instance: Instance<'_>) -> MonoItem<'_> {
+fn create_fn_mono_item(instance: Instance<'_>, source: Span) -> Spanned<MonoItem<'_>> {
     debug!("create_fn_mono_item(instance={})", instance);
-    MonoItem::Fn(instance)
+    respan(source, MonoItem::Fn(instance))
 }
 
 /// Creates a `MonoItem` for each method that is referenced by the vtable for
@@ -897,7 +914,8 @@ fn create_mono_items_for_vtable_methods<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ty: Ty<'tcx>,
     impl_ty: Ty<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     assert!(
         !trait_ty.needs_subst()
@@ -927,12 +945,12 @@ fn create_mono_items_for_vtable_methods<'tcx>(
                     .unwrap()
                 })
                 .filter(|&instance| should_monomorphize_locally(tcx, &instance))
-                .map(create_fn_mono_item);
+                .map(|item| create_fn_mono_item(item, source));
             output.extend(methods);
         }
 
         // Also add the destructor.
-        visit_drop_use(tcx, impl_ty, false, output);
+        visit_drop_use(tcx, impl_ty, false, source, output);
     }
 }
 
@@ -943,7 +961,7 @@ fn create_mono_items_for_vtable_methods<'tcx>(
 struct RootCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     mode: MonoItemCollectionMode,
-    output: &'a mut Vec<MonoItem<'tcx>>,
+    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
     entry_fn: Option<(LocalDefId, EntryFnType)>,
 }
 
@@ -980,7 +998,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
 
                         let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty())
                             .monomorphic_ty(self.tcx);
-                        visit_drop_use(self.tcx, ty, true, self.output);
+                        visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
                     }
                 }
             }
@@ -989,12 +1007,12 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
                     "RootCollector: ItemKind::GlobalAsm({})",
                     def_id_to_string(self.tcx, self.tcx.hir().local_def_id(item.hir_id))
                 );
-                self.output.push(MonoItem::GlobalAsm(item.hir_id));
+                self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id)));
             }
             hir::ItemKind::Static(..) => {
                 let def_id = self.tcx.hir().local_def_id(item.hir_id);
                 debug!("RootCollector: ItemKind::Static({})", def_id_to_string(self.tcx, def_id));
-                self.output.push(MonoItem::Static(def_id.to_def_id()));
+                self.output.push(dummy_spanned(MonoItem::Static(def_id.to_def_id())));
             }
             hir::ItemKind::Const(..) => {
                 // const items only generate mono items if they are
@@ -1051,7 +1069,7 @@ impl RootCollector<'_, 'v> {
             debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
 
             let instance = Instance::mono(self.tcx, def_id.to_def_id());
-            self.output.push(create_fn_mono_item(instance));
+            self.output.push(create_fn_mono_item(instance, DUMMY_SP));
         }
     }
 
@@ -1088,7 +1106,7 @@ impl RootCollector<'_, 'v> {
         .unwrap()
         .unwrap();
 
-        self.output.push(create_fn_mono_item(start_instance));
+        self.output.push(create_fn_mono_item(start_instance, DUMMY_SP));
     }
 }
 
@@ -1100,7 +1118,7 @@ fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 fn create_mono_items_for_default_impls<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &'tcx hir::Item<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     match item.kind {
         hir::ItemKind::Impl { ref generics, ref items, .. } => {
@@ -1145,8 +1163,9 @@ fn create_mono_items_for_default_impls<'tcx>(
                         .unwrap()
                         .unwrap();
 
-                    let mono_item = create_fn_mono_item(instance);
-                    if mono_item.is_instantiable(tcx) && should_monomorphize_locally(tcx, &instance)
+                    let mono_item = create_fn_mono_item(instance, DUMMY_SP);
+                    if mono_item.node.is_instantiable(tcx)
+                        && should_monomorphize_locally(tcx, &instance)
                     {
                         output.push(mono_item);
                     }
@@ -1158,14 +1177,18 @@ fn create_mono_items_for_default_impls<'tcx>(
 }
 
 /// Scans the miri alloc in order to find function calls, closures, and drop-glue.
-fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<MonoItem<'tcx>>) {
+fn collect_miri<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    alloc_id: AllocId,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+) {
     match tcx.global_alloc(alloc_id) {
         GlobalAlloc::Static(def_id) => {
             assert!(!tcx.is_thread_local_static(def_id));
             let instance = Instance::mono(tcx, def_id);
             if should_monomorphize_locally(tcx, &instance) {
                 trace!("collecting static {:?}", def_id);
-                output.push(MonoItem::Static(def_id));
+                output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
         }
         GlobalAlloc::Memory(alloc) => {
@@ -1179,7 +1202,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon
         GlobalAlloc::Function(fn_instance) => {
             if should_monomorphize_locally(tcx, &fn_instance) {
                 trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
-                output.push(create_fn_mono_item(fn_instance));
+                output.push(create_fn_mono_item(fn_instance, DUMMY_SP));
             }
         }
     }
@@ -1189,7 +1212,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon
 fn collect_neighbours<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     debug!("collect_neighbours: {:?}", instance.def_id());
     let body = tcx.instance_mir(instance.def);
@@ -1207,7 +1230,7 @@ fn def_id_to_string(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
 fn collect_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     value: ConstValue<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     match value {
         ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output),
diff --git a/src/test/ui/infinite/infinite-instantiation.rs b/src/test/ui/infinite/infinite-instantiation.rs
index 6f53680f7c8..9fee01c1ba6 100644
--- a/src/test/ui/infinite/infinite-instantiation.rs
+++ b/src/test/ui/infinite/infinite-instantiation.rs
@@ -1,9 +1,3 @@
-//
-// We get an error message at the top of file (dummy span).
-// This is not helpful, but also kind of annoying to prevent,
-// so for now just live with it.
-// This test case was originally for issue #2258.
-
 // build-fail
 
 trait ToOpt: Sized {
@@ -23,11 +17,9 @@ impl<T:Clone> ToOpt for Option<T> {
 }
 
 fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-//~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
     if counter > 0 {
         function(counter - 1, t.to_option());
-        // FIXME(#4287) Error message should be here. It should be
-        // a type error to instantiate `test` at a type other than T.
+        //~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
     }
 }
 
diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr
index ae81c680a7b..7b22393ee7c 100644
--- a/src/test/ui/infinite/infinite-instantiation.stderr
+++ b/src/test/ui/infinite/infinite-instantiation.stderr
@@ -1,11 +1,16 @@
 error: reached the recursion limit while instantiating `function::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<usize>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
-  --> $DIR/infinite-instantiation.rs:25:1
+  --> $DIR/infinite-instantiation.rs:21:9
+   |
+LL |         function(counter - 1, t.to_option());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `function` defined here
+  --> $DIR/infinite-instantiation.rs:19:1
    |
 LL | / fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-LL | |
 LL | |     if counter > 0 {
 LL | |         function(counter - 1, t.to_option());
-...  |
+LL | |
 LL | |     }
 LL | | }
    | |_^
diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs
index 1400c6f97b6..b0fcb74764b 100644
--- a/src/test/ui/issues/issue-67552.rs
+++ b/src/test/ui/issues/issue-67552.rs
@@ -18,7 +18,6 @@ fn identity<T>(x: T) -> T {
 }
 
 fn rec<T>(mut it: T)
-//~^ ERROR reached the recursion limit while instantiating
 where
     T: Iterator,
 {
@@ -26,5 +25,6 @@ where
         T::count(it);
     } else {
         rec(identity(&mut it))
+        //~^ ERROR reached the recursion limit while instantiating
     }
 }
diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr
index 881f9d221d6..3bb2016f07d 100644
--- a/src/test/ui/issues/issue-67552.stderr
+++ b/src/test/ui/issues/issue-67552.stderr
@@ -1,10 +1,16 @@
 error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>`
+  --> $DIR/issue-67552.rs:27:9
+   |
+LL |         rec(identity(&mut it))
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `rec` defined here
   --> $DIR/issue-67552.rs:20:1
    |
 LL | / fn rec<T>(mut it: T)
-LL | |
 LL | | where
 LL | |     T: Iterator,
+LL | | {
 ...  |
 LL | |     }
 LL | | }
diff --git a/src/test/ui/issues/issue-8727.rs b/src/test/ui/issues/issue-8727.rs
index 80f360155cb..14bdd851111 100644
--- a/src/test/ui/issues/issue-8727.rs
+++ b/src/test/ui/issues/issue-8727.rs
@@ -3,12 +3,10 @@
 
 // build-fail
 
-fn generic<T>() {
+fn generic<T>() { //~ WARN function cannot return without recursing
     generic::<Option<T>>();
 }
-//~^^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
-//~| WARN function cannot return without recursing
-
+//~^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
 
 
 fn main () {
diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr
index ee0672c598d..70709fd33ac 100644
--- a/src/test/ui/issues/issue-8727.stderr
+++ b/src/test/ui/issues/issue-8727.stderr
@@ -10,6 +10,12 @@ LL |     generic::<Option<T>>();
    = help: a `loop` may express intention better if this is on purpose
 
 error: reached the recursion limit while instantiating `generic::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+  --> $DIR/issue-8727.rs:7:5
+   |
+LL |     generic::<Option<T>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `generic` defined here
   --> $DIR/issue-8727.rs:6:1
    |
 LL | / fn generic<T>() {
diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
index de6df4cd026..0552847c48c 100644
--- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
+++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
@@ -1,4 +1,22 @@
 error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::<S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>> - shim(Some(S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>))`
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | |     // Code here does not matter - this is replaced by the
+LL | |     // real drop glue by the compiler.
+LL | |     drop_in_place(to_drop)
+LL | | }
+   | |_^
+   |
+note: `std::intrinsics::drop_in_place` defined here
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | |     // Code here does not matter - this is replaced by the
+LL | |     // real drop glue by the compiler.
+LL | |     drop_in_place(to_drop)
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/recursion/recursion.rs b/src/test/ui/recursion/recursion.rs
index bf1eaef367d..373cc17d0e0 100644
--- a/src/test/ui/recursion/recursion.rs
+++ b/src/test/ui/recursion/recursion.rs
@@ -12,11 +12,10 @@ impl<T:Dot> Dot for Cons<T> {
     self.head * other.head + self.tail.dot(other.tail)
   }
 }
-fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize { //~ ERROR recursion limit
+fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
   match n {    0 => {first.dot(second)}
-      // FIXME(#4287) Error message should be here. It should be
-      // a type error to instantiate `test` at a type other than T.
     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+    //~^ ERROR recursion limit
   }
 }
 pub fn main() {
diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr
index 1a65b0e84f6..0c0eba68c83 100644
--- a/src/test/ui/recursion/recursion.stderr
+++ b/src/test/ui/recursion/recursion.stderr
@@ -1,11 +1,16 @@
 error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Nil>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+  --> $DIR/recursion.rs:17:11
+   |
+LL |     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `test` defined here
   --> $DIR/recursion.rs:15:1
    |
 LL | / fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
 LL | |   match n {    0 => {first.dot(second)}
-LL | |       // FIXME(#4287) Error message should be here. It should be
-LL | |       // a type error to instantiate `test` at a type other than T.
 LL | |     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+LL | |
 LL | |   }
 LL | | }
    | |_^