Auto merge of #70667 - flip1995:clippyup, r=Manishearth

Update Clippy

r? @Manishearth

Closes #70663
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 350f7be..6501ba0 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -79,7 +79,7 @@
     };
 
     match layout.fields {
-        layout::FieldPlacement::Union(_) => {
+        layout::FieldsShape::Union(_) => {
             let fill = cx.type_padding_filler(layout.size, layout.align.abi);
             let packed = false;
             match name {
@@ -91,10 +91,10 @@
                 }
             }
         }
-        layout::FieldPlacement::Array { count, .. } => {
+        layout::FieldsShape::Array { count, .. } => {
             cx.type_array(layout.field(cx, 0).llvm_type(cx), count)
         }
-        layout::FieldPlacement::Arbitrary { .. } => match name {
+        layout::FieldsShape::Arbitrary { .. } => match name {
             None => {
                 let (llfields, packed) = struct_llfields(cx, layout);
                 cx.type_struct(&llfields, packed)
@@ -371,13 +371,13 @@
             _ => {}
         }
         match self.fields {
-            layout::FieldPlacement::Union(_) => {
+            layout::FieldsShape::Union(_) => {
                 bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self)
             }
 
-            layout::FieldPlacement::Array { .. } => index as u64,
+            layout::FieldsShape::Array { .. } => index as u64,
 
-            layout::FieldPlacement::Arbitrary { .. } => {
+            layout::FieldsShape::Arbitrary { .. } => {
                 1 + (self.fields.memory_index(index) as u64) * 2
             }
         }
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 1237e70..eca66a5 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -66,7 +66,7 @@
     }
 
     pub fn len<Cx: ConstMethods<'tcx, Value = V>>(&self, cx: &Cx) -> V {
-        if let layout::FieldPlacement::Array { count, .. } = self.layout.fields {
+        if let layout::FieldsShape::Array { count, .. } = self.layout.fields {
             if self.layout.is_unsized() {
                 assert_eq!(count, 0);
                 self.llextra.unwrap()
diff --git a/src/librustc_error_codes/error_codes/E0468.md b/src/librustc_error_codes/error_codes/E0468.md
index 73e3ebb..cf86647 100644
--- a/src/librustc_error_codes/error_codes/E0468.md
+++ b/src/librustc_error_codes/error_codes/E0468.md
@@ -1,4 +1,4 @@
-A non-root module attempts to import macros from another crate.
+A non-root module tried to import macros from another crate.
 
 Example of erroneous code:
 
@@ -17,7 +17,7 @@
 This will work:
 
 ```
-#[macro_use(debug_assert)]
+#[macro_use(debug_assert)] // ok!
 extern crate core;
 
 mod foo {
diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs
index c46ab89..d46f1bc 100644
--- a/src/librustc_middle/mir/interpret/error.rs
+++ b/src/librustc_middle/mir/interpret/error.rs
@@ -53,9 +53,8 @@
 
 #[derive(Debug)]
 pub struct FrameInfo<'tcx> {
-    /// This span is in the caller.
-    pub call_site: Span,
     pub instance: ty::Instance<'tcx>,
+    pub span: Span,
     pub lint_root: Option<hir::HirId>,
 }
 
@@ -65,12 +64,12 @@
             if tcx.def_key(self.instance.def_id()).disambiguated_data.data
                 == DefPathData::ClosureExpr
             {
-                write!(f, "inside call to closure")?;
+                write!(f, "inside closure")?;
             } else {
-                write!(f, "inside call to `{}`", self.instance)?;
+                write!(f, "inside `{}`", self.instance)?;
             }
-            if !self.call_site.is_dummy() {
-                let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo());
+            if !self.span.is_dummy() {
+                let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
                 write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
             }
             Ok(())
@@ -168,13 +167,10 @@
             if let Some(span_msg) = span_msg {
                 err.span_label(self.span, span_msg);
             }
-            // Add spans for the stacktrace.
-            // Skip the last, which is just the environment of the constant.  The stacktrace
-            // is sometimes empty because we create "fake" eval contexts in CTFE to do work
-            // on constant values.
-            if !self.stacktrace.is_empty() {
-                for frame_info in &self.stacktrace[..self.stacktrace.len() - 1] {
-                    err.span_label(frame_info.call_site, frame_info.to_string());
+            // Add spans for the stacktrace. Don't print a single-line backtrace though.
+            if self.stacktrace.len() > 1 {
+                for frame_info in &self.stacktrace {
+                    err.span_label(frame_info.span, frame_info.to_string());
                 }
             }
             // Let the caller finish the job.
diff --git a/src/librustc_middle/traits/specialization_graph.rs b/src/librustc_middle/traits/specialization_graph.rs
index 1847326..a2793f9 100644
--- a/src/librustc_middle/traits/specialization_graph.rs
+++ b/src/librustc_middle/traits/specialization_graph.rs
@@ -154,14 +154,44 @@
     }
 }
 
-pub struct NodeItem<T> {
-    pub node: Node,
-    pub item: T,
+/// Information about the most specialized definition of an associated item.
+pub struct LeafDef {
+    /// The associated item described by this `LeafDef`.
+    pub item: ty::AssocItem,
+
+    /// The node in the specialization graph containing the definition of `item`.
+    pub defining_node: Node,
+
+    /// The "top-most" (ie. least specialized) specialization graph node that finalized the
+    /// definition of `item`.
+    ///
+    /// Example:
+    ///
+    /// ```
+    /// trait Tr {
+    ///     fn assoc(&self);
+    /// }
+    ///
+    /// impl<T> Tr for T {
+    ///     default fn assoc(&self) {}
+    /// }
+    ///
+    /// impl Tr for u8 {}
+    /// ```
+    ///
+    /// If we start the leaf definition search at `impl Tr for u8`, that impl will be the
+    /// `finalizing_node`, while `defining_node` will be the generic impl.
+    ///
+    /// If the leaf definition search is started at the generic impl, `finalizing_node` will be
+    /// `None`, since the most specialized impl we found still allows overriding the method
+    /// (doesn't finalize it).
+    pub finalizing_node: Option<Node>,
 }
 
-impl<T> NodeItem<T> {
-    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
-        NodeItem { node: self.node, item: f(self.item) }
+impl LeafDef {
+    /// Returns whether this definition is known to not be further specializable.
+    pub fn is_final(&self) -> bool {
+        self.finalizing_node.is_some()
     }
 }
 
@@ -173,18 +203,36 @@
         tcx: TyCtxt<'tcx>,
         trait_item_name: Ident,
         trait_item_kind: ty::AssocKind,
-    ) -> Option<NodeItem<ty::AssocItem>> {
+    ) -> Option<LeafDef> {
         let trait_def_id = self.trait_def_id;
+        let mut finalizing_node = None;
+
         self.find_map(|node| {
-            node.item(tcx, trait_item_name, trait_item_kind, trait_def_id)
-                .map(|item| NodeItem { node, item })
+            if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) {
+                if finalizing_node.is_none() {
+                    let is_specializable = item.defaultness.is_default()
+                        || tcx.impl_defaultness(node.def_id()).is_default();
+
+                    if !is_specializable {
+                        finalizing_node = Some(node);
+                    }
+                }
+
+                Some(LeafDef { item, defining_node: node, finalizing_node })
+            } else {
+                // Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
+                finalizing_node = Some(node);
+                None
+            }
         })
     }
 }
 
 /// Walk up the specialization ancestors of a given impl, starting with that
-/// impl itself. Returns `None` if an error was reported while building the
-/// specialization graph.
+/// impl itself.
+///
+/// Returns `Err` if an error was reported while building the specialization
+/// graph.
 pub fn ancestors(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 17c9392..727d302 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -230,7 +230,7 @@
 // Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`.
 // This is used to go between `memory_index` (source field order to memory order)
 // and `inverse_memory_index` (memory order to source field order).
-// See also `FieldPlacement::Arbitrary::memory_index` for more details.
+// See also `FieldsShape::Arbitrary::memory_index` for more details.
 // FIXME(eddyb) build a better abstraction for permutations, if possible.
 fn invert_mapping(map: &[u32]) -> Vec<u32> {
     let mut inverse = vec![0; map.len()];
@@ -257,7 +257,7 @@
 
         Layout {
             variants: Variants::Single { index: VariantIdx::new(0) },
-            fields: FieldPlacement::Arbitrary {
+            fields: FieldsShape::Arbitrary {
                 offsets: vec![Size::ZERO, b_offset],
                 memory_index: vec![0, 1],
             },
@@ -443,7 +443,7 @@
                         };
                         let pair = self.scalar_pair(a.clone(), b.clone());
                         let pair_offsets = match pair.fields {
-                            FieldPlacement::Arbitrary { ref offsets, ref memory_index } => {
+                            FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
                                 assert_eq!(memory_index, &[0, 1]);
                                 offsets
                             }
@@ -471,7 +471,7 @@
 
         Ok(Layout {
             variants: Variants::Single { index: VariantIdx::new(0) },
-            fields: FieldPlacement::Arbitrary { offsets, memory_index },
+            fields: FieldsShape::Arbitrary { offsets, memory_index },
             abi,
             largest_niche,
             align,
@@ -520,7 +520,7 @@
             // The never type.
             ty::Never => tcx.intern_layout(Layout {
                 variants: Variants::Single { index: VariantIdx::new(0) },
-                fields: FieldPlacement::Union(0),
+                fields: FieldsShape::Union(0),
                 abi: Abi::Uninhabited,
                 largest_niche: None,
                 align: dl.i8_align,
@@ -581,7 +581,7 @@
 
                 tcx.intern_layout(Layout {
                     variants: Variants::Single { index: VariantIdx::new(0) },
-                    fields: FieldPlacement::Array { stride: element.size, count },
+                    fields: FieldsShape::Array { stride: element.size, count },
                     abi,
                     largest_niche,
                     align: element.align,
@@ -592,7 +592,7 @@
                 let element = self.layout_of(element)?;
                 tcx.intern_layout(Layout {
                     variants: Variants::Single { index: VariantIdx::new(0) },
-                    fields: FieldPlacement::Array { stride: element.size, count: 0 },
+                    fields: FieldsShape::Array { stride: element.size, count: 0 },
                     abi: Abi::Aggregate { sized: false },
                     largest_niche: None,
                     align: element.align,
@@ -601,7 +601,7 @@
             }
             ty::Str => tcx.intern_layout(Layout {
                 variants: Variants::Single { index: VariantIdx::new(0) },
-                fields: FieldPlacement::Array { stride: Size::from_bytes(1), count: 0 },
+                fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
                 abi: Abi::Aggregate { sized: false },
                 largest_niche: None,
                 align: dl.i8_align,
@@ -670,7 +670,7 @@
 
                 tcx.intern_layout(Layout {
                     variants: Variants::Single { index: VariantIdx::new(0) },
-                    fields: FieldPlacement::Array { stride: element.size, count },
+                    fields: FieldsShape::Array { stride: element.size, count },
                     abi: Abi::Vector { element: scalar, count },
                     largest_niche: element.largest_niche.clone(),
                     size,
@@ -746,7 +746,7 @@
 
                     return Ok(tcx.intern_layout(Layout {
                         variants: Variants::Single { index },
-                        fields: FieldPlacement::Union(variants[index].len()),
+                        fields: FieldsShape::Union(variants[index].len()),
                         abi,
                         largest_niche: None,
                         align,
@@ -980,7 +980,7 @@
                                     discr_index: 0,
                                     variants: st,
                                 },
-                                fields: FieldPlacement::Arbitrary {
+                                fields: FieldsShape::Arbitrary {
                                     offsets: vec![offset],
                                     memory_index: vec![0],
                                 },
@@ -1121,7 +1121,7 @@
                     let new_ity_size = ity.size();
                     for variant in &mut layout_variants {
                         match variant.fields {
-                            FieldPlacement::Arbitrary { ref mut offsets, .. } => {
+                            FieldsShape::Arbitrary { ref mut offsets, .. } => {
                                 for i in offsets {
                                     if *i <= old_ity_size {
                                         assert_eq!(*i, old_ity_size);
@@ -1151,7 +1151,7 @@
                     let mut common_prim = None;
                     for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) {
                         let offsets = match layout_variant.fields {
-                            FieldPlacement::Arbitrary { ref offsets, .. } => offsets,
+                            FieldsShape::Arbitrary { ref offsets, .. } => offsets,
                             _ => bug!(),
                         };
                         let mut fields =
@@ -1187,7 +1187,7 @@
                     if let Some((prim, offset)) = common_prim {
                         let pair = self.scalar_pair(tag.clone(), scalar_unit(prim));
                         let pair_offsets = match pair.fields {
-                            FieldPlacement::Arbitrary { ref offsets, ref memory_index } => {
+                            FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
                                 assert_eq!(memory_index, &[0, 1]);
                                 offsets
                             }
@@ -1218,7 +1218,7 @@
                         discr_index: 0,
                         variants: layout_variants,
                     },
-                    fields: FieldPlacement::Arbitrary {
+                    fields: FieldsShape::Arbitrary {
                         offsets: vec![Size::ZERO],
                         memory_index: vec![0],
                     },
@@ -1435,7 +1435,7 @@
         // GeneratorLayout.
         debug!("prefix = {:#?}", prefix);
         let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
-            FieldPlacement::Arbitrary { mut offsets, memory_index } => {
+            FieldsShape::Arbitrary { mut offsets, memory_index } => {
                 let mut inverse_memory_index = invert_mapping(&memory_index);
 
                 // "a" (`0..b_start`) and "b" (`b_start..`) correspond to
@@ -1458,7 +1458,7 @@
                 let memory_index_b = invert_mapping(&inverse_memory_index_b);
 
                 let outer_fields =
-                    FieldPlacement::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
+                    FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
                 (outer_fields, offsets_b, memory_index_b)
             }
             _ => bug!(),
@@ -1492,7 +1492,7 @@
                 variant.variants = Variants::Single { index };
 
                 let (offsets, memory_index) = match variant.fields {
-                    FieldPlacement::Arbitrary { offsets, memory_index } => (offsets, memory_index),
+                    FieldsShape::Arbitrary { offsets, memory_index } => (offsets, memory_index),
                     _ => bug!(),
                 };
 
@@ -1535,7 +1535,7 @@
                 combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX);
                 let combined_memory_index = invert_mapping(&combined_inverse_memory_index);
 
-                variant.fields = FieldPlacement::Arbitrary {
+                variant.fields = FieldsShape::Arbitrary {
                     offsets: combined_offsets,
                     memory_index: combined_memory_index,
                 };
@@ -1990,7 +1990,7 @@
                 if index == variant_index &&
                 // Don't confuse variants of uninhabited enums with the enum itself.
                 // For more details see https://github.com/rust-lang/rust/issues/69763.
-                this.fields != FieldPlacement::Union(0) =>
+                this.fields != FieldsShape::Union(0) =>
             {
                 this.layout
             }
@@ -2008,7 +2008,7 @@
                 let tcx = cx.tcx();
                 tcx.intern_layout(Layout {
                     variants: Variants::Single { index: variant_index },
-                    fields: FieldPlacement::Union(fields),
+                    fields: FieldsShape::Union(fields),
                     abi: Abi::Uninhabited,
                     largest_niche: None,
                     align: tcx.data_layout.i8_align,
@@ -2054,7 +2054,7 @@
                 // Reuse the fat `*T` type as its own thin pointer data field.
                 // This provides information about, e.g., DST struct pointees
                 // (which may have no non-DST form), and will work as long
-                // as the `Abi` or `FieldPlacement` is checked by users.
+                // as the `Abi` or `FieldsShape` is checked by users.
                 if i == 0 {
                     let nil = tcx.mk_unit();
                     let ptr_ty = if this.ty.is_unsafe_ptr() {
@@ -2219,7 +2219,7 @@
 
                 if let Some(variant) = data_variant {
                     // We're not interested in any unions.
-                    if let FieldPlacement::Union(_) = variant.fields {
+                    if let FieldsShape::Union(_) = variant.fields {
                         data_variant = None;
                     }
                 }
diff --git a/src/librustc_mir/const_eval/error.rs b/src/librustc_mir/const_eval/error.rs
index f722784..f7e28cf 100644
--- a/src/librustc_mir/const_eval/error.rs
+++ b/src/librustc_mir/const_eval/error.rs
@@ -55,6 +55,6 @@
     mut error: InterpErrorInfo<'tcx>,
 ) -> ConstEvalErr<'tcx> {
     error.print_backtrace();
-    let stacktrace = ecx.generate_stacktrace(None);
+    let stacktrace = ecx.generate_stacktrace();
     ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
 }
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index c30d41e..af79198 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -46,7 +46,6 @@
 
     ecx.push_stack_frame(
         cid.instance,
-        body.span,
         body,
         Some(ret.into()),
         StackPopCleanup::None { cleanup: false },
diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs
index ee6fab4..e926347 100644
--- a/src/librustc_mir/const_eval/machine.rs
+++ b/src/librustc_mir/const_eval/machine.rs
@@ -8,9 +8,9 @@
 use rustc_data_structures::fx::FxHashMap;
 
 use rustc_ast::ast::Mutability;
+use rustc_hir::def_id::DefId;
 use rustc_middle::mir::AssertMessage;
 use rustc_span::symbol::Symbol;
-use rustc_span::{def_id::DefId, Span};
 
 use crate::interpret::{
     self, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, OpTy,
@@ -64,7 +64,6 @@
     /// If this returns successfully (`Ok`), the function should just be evaluated normally.
     fn hook_panic_fn(
         &mut self,
-        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
     ) -> InterpResult<'tcx> {
@@ -77,7 +76,7 @@
 
             let msg_place = self.deref_operand(args[0])?;
             let msg = Symbol::intern(self.read_str(msg_place)?);
-            let span = self.find_closest_untracked_caller_location().unwrap_or(span);
+            let span = self.find_closest_untracked_caller_location();
             let (file, line, col) = self.location_triple_for_span(span);
             Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
         } else {
@@ -191,7 +190,6 @@
 
     fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
@@ -213,7 +211,7 @@
             } else {
                 // Some functions we support even if they are non-const -- but avoid testing
                 // that for const fn!
-                ecx.hook_panic_fn(span, instance, args)?;
+                ecx.hook_panic_fn(instance, args)?;
                 // We certainly do *not* want to actually call the fn
                 // though, so be sure we return here.
                 throw_unsup_format!("calling non-const function `{}`", instance)
@@ -248,13 +246,12 @@
 
     fn call_intrinsic(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
-        if ecx.emulate_intrinsic(span, instance, args, ret)? {
+        if ecx.emulate_intrinsic(instance, args, ret)? {
             return Ok(());
         }
         // An intrinsic that we do not support
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index d204be7..8f24fc4 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -17,7 +17,7 @@
 use rustc_middle::ty::query::TyCtxtAt;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc_span::source_map::{self, Span, DUMMY_SP};
+use rustc_span::source_map::DUMMY_SP;
 
 use super::{
     Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
@@ -57,9 +57,6 @@
     /// The def_id and substs of the current function.
     pub instance: ty::Instance<'tcx>,
 
-    /// The span of the call site.
-    pub span: source_map::Span,
-
     /// Extra data for the machine.
     pub extra: Extra,
 
@@ -502,7 +499,6 @@
     pub fn push_stack_frame(
         &mut self,
         instance: ty::Instance<'tcx>,
-        span: Span,
         body: &'mir mir::Body<'tcx>,
         return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
@@ -522,7 +518,6 @@
             // empty local array, we fill it in below, after we are inside the stack frame and
             // all methods actually know about the frame
             locals: IndexVec::new(),
-            span,
             instance,
             stmt: 0,
             extra,
@@ -541,7 +536,6 @@
                 // statics and constants don't have `Storage*` statements, no need to look for them
                 Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => {}
                 _ => {
-                    trace!("push_stack_frame: {:?}: num_bbs: {}", span, body.basic_blocks().len());
                     for block in body.basic_blocks() {
                         for stmt in block.statements.iter() {
                             use rustc_middle::mir::StatementKind::{StorageDead, StorageLive};
@@ -859,33 +853,21 @@
         }
     }
 
-    pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> Vec<FrameInfo<'tcx>> {
-        let mut last_span = None;
+    pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
         let mut frames = Vec::new();
         for frame in self.stack().iter().rev() {
-            // make sure we don't emit frames that are duplicates of the previous
-            if explicit_span == Some(frame.span) {
-                last_span = Some(frame.span);
-                continue;
-            }
-            if let Some(last) = last_span {
-                if last == frame.span {
-                    continue;
-                }
-            } else {
-                last_span = Some(frame.span);
-            }
-
-            let lint_root = frame.current_source_info().and_then(|source_info| {
+            let source_info = frame.current_source_info();
+            let lint_root = source_info.and_then(|source_info| {
                 match &frame.body.source_scopes[source_info.scope].local_data {
                     mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
                     mir::ClearCrossCrate::Clear => None,
                 }
             });
+            let span = source_info.map_or(DUMMY_SP, |source_info| source_info.span);
 
-            frames.push(FrameInfo { call_site: frame.span, instance: frame.instance, lint_root });
+            frames.push(FrameInfo { span, instance: frame.instance, lint_root });
         }
-        trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
+        trace!("generate stacktrace: {:#?}", frames);
         frames
     }
 }
@@ -899,7 +881,6 @@
     fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) {
         self.body.hash_stable(hcx, hasher);
         self.instance.hash_stable(hcx, hasher);
-        self.span.hash_stable(hcx, hasher);
         self.return_to_block.hash_stable(hcx, hasher);
         self.return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher);
         self.locals.hash_stable(hcx, hasher);
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index c5f7a94..b60377f 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -15,7 +15,6 @@
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
 
 use super::{ImmTy, InterpCx, Machine, OpTy, PlaceTy};
 
@@ -78,7 +77,6 @@
     /// Returns `true` if emulation happened.
     pub fn emulate_intrinsic(
         &mut self,
-        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::PointerTag>],
         ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
@@ -101,7 +99,7 @@
         // `src/librustc_middle/ty/constness.rs`
         match intrinsic_name {
             sym::caller_location => {
-                let span = self.find_closest_untracked_caller_location().unwrap_or(span);
+                let span = self.find_closest_untracked_caller_location();
                 let location = self.alloc_caller_location_for_span(span);
                 self.write_scalar(location.ptr, dest)?;
             }
@@ -118,7 +116,7 @@
                     sym::needs_drop => self.tcx.types.bool,
                     sym::type_id => self.tcx.types.u64,
                     sym::type_name => self.tcx.mk_static_str(),
-                    _ => span_bug!(span, "Already checked for nullary intrinsics"),
+                    _ => bug!("already checked for nullary intrinsics"),
                 };
                 let val = self.const_eval(gid, ty)?;
                 self.copy_op(val, dest)?;
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
index 37b01d6..f7e264b 100644
--- a/src/librustc_mir/interpret/intrinsics/caller_location.rs
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -12,18 +12,21 @@
 
 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
-    /// frame which is not `#[track_caller]`. If the first frame found lacks `#[track_caller]`, then
-    /// `None` is returned and the callsite of the function invocation itself should be used.
-    crate fn find_closest_untracked_caller_location(&self) -> Option<Span> {
-        let mut caller_span = None;
-        for next_caller in self.stack.iter().rev() {
-            if !next_caller.instance.def.requires_caller_location(*self.tcx) {
-                return caller_span;
-            }
-            caller_span = Some(next_caller.span);
-        }
-
-        caller_span
+    /// frame which is not `#[track_caller]`.
+    crate fn find_closest_untracked_caller_location(&self) -> Span {
+        self.stack
+            .iter()
+            .rev()
+            // Find first non-`#[track_caller]` frame.
+            .find(|frame| !frame.instance.def.requires_caller_location(*self.tcx))
+            // Assert that there is always such a frame.
+            .unwrap()
+            .current_source_info()
+            // Assert that the frame we look at is actually executing code currently
+            // (`current_source_info` is None when we are unwinding and the frame does
+            // not require cleanup).
+            .unwrap()
+            .span
     }
 
     /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index faee041..48082a1 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -7,7 +7,7 @@
 
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::{def_id::DefId, Span};
+use rustc_span::def_id::DefId;
 
 use super::{
     AllocId, Allocation, AllocationExtra, Frame, ImmTy, InterpCx, InterpResult, Memory, MemoryKind,
@@ -135,7 +135,6 @@
     /// was used.
     fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
@@ -156,7 +155,6 @@
     /// responsibility to advance the instruction pointer as appropriate.
     fn call_intrinsic(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 5c4915d..a8e65a7 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -219,7 +219,7 @@
             // Go through the layout.  There are lots of types that support a length,
             // e.g., SIMD types.
             match self.layout.fields {
-                layout::FieldPlacement::Array { count, .. } => Ok(count),
+                layout::FieldsShape::Array { count, .. } => Ok(count),
                 _ => bug!("len not supported on sized type {:?}", self.layout.ty),
             }
         }
@@ -437,7 +437,7 @@
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Not using the layout method because we want to compute on u64
         match base.layout.fields {
-            layout::FieldPlacement::Array { stride, .. } => {
+            layout::FieldsShape::Array { stride, .. } => {
                 let len = base.len(self)?;
                 if index >= len {
                     // This can only be reached in ConstProp and non-rustc-MIR.
@@ -463,7 +463,7 @@
     {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let stride = match base.layout.fields {
-            layout::FieldPlacement::Array { stride, .. } => stride,
+            layout::FieldsShape::Array { stride, .. } => stride,
             _ => bug!("mplace_array_fields: expected an array layout"),
         };
         let layout = base.layout.field(self, 0)?;
@@ -493,7 +493,7 @@
         // Not using layout method because that works with usize, and does not work with slices
         // (that have count 0 in their layout).
         let from_offset = match base.layout.fields {
-            layout::FieldPlacement::Array { stride, .. } => stride * from, // `Size` multiplication is checked
+            layout::FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked
             _ => bug!("Unexpected layout of index access: {:#?}", base.layout),
         };
 
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 0c2aa28..6ca6f50 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -4,7 +4,6 @@
 use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
 use rustc_middle::ty::Instance;
 use rustc_middle::{mir, ty};
-use rustc_span::source_map::Span;
 use rustc_target::spec::abi::Abi;
 
 use super::{
@@ -71,14 +70,7 @@
                     Some((dest, ret)) => Some((self.eval_place(dest)?, ret)),
                     None => None,
                 };
-                self.eval_fn_call(
-                    fn_val,
-                    terminator.source_info.span,
-                    abi,
-                    &args[..],
-                    ret,
-                    *cleanup,
-                )?;
+                self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
             }
 
             Drop { location, target, unwind } => {
@@ -88,7 +80,7 @@
                 trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
 
                 let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
-                self.drop_in_place(place, instance, terminator.source_info.span, target, unwind)?;
+                self.drop_in_place(place, instance, target, unwind)?;
             }
 
             Assert { ref cond, expected, ref msg, target, cleanup } => {
@@ -196,7 +188,6 @@
     fn eval_fn_call(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
-        span: Span,
         caller_abi: Abi,
         args: &[OpTy<'tcx, M::PointerTag>],
         ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
@@ -242,7 +233,7 @@
         match instance.def {
             ty::InstanceDef::Intrinsic(..) => {
                 assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
-                M::call_intrinsic(self, span, instance, args, ret, unwind)
+                M::call_intrinsic(self, instance, args, ret, unwind)
             }
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
@@ -252,14 +243,13 @@
             | ty::InstanceDef::CloneShim(..)
             | ty::InstanceDef::Item(_) => {
                 // We need MIR for this fn
-                let body = match M::find_mir_or_eval_fn(self, span, instance, args, ret, unwind)? {
+                let body = match M::find_mir_or_eval_fn(self, instance, args, ret, unwind)? {
                     Some(body) => body,
                     None => return Ok(()),
                 };
 
                 self.push_stack_frame(
                     instance,
-                    span,
                     body,
                     ret.map(|p| p.0),
                     StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind },
@@ -407,7 +397,7 @@
                     OpTy::from(ImmTy { layout: this_receiver_ptr, imm: receiver_place.ptr.into() });
                 trace!("Patched self operand to {:#?}", args[0]);
                 // recurse with concrete function
-                self.eval_fn_call(drop_fn, span, caller_abi, &args, ret, unwind)
+                self.eval_fn_call(drop_fn, caller_abi, &args, ret, unwind)
             }
         }
     }
@@ -416,7 +406,6 @@
         &mut self,
         place: PlaceTy<'tcx, M::PointerTag>,
         instance: ty::Instance<'tcx>,
-        span: Span,
         target: mir::BasicBlock,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
@@ -444,7 +433,6 @@
 
         self.eval_fn_call(
             FnVal::Instance(instance),
-            span,
             Abi::Rust,
             &[arg.into()],
             Some((dest.into(), target)),
diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs
index 1117016..66a46c1 100644
--- a/src/librustc_mir/interpret/visitor.rs
+++ b/src/librustc_mir/interpret/visitor.rs
@@ -207,10 +207,10 @@
 
                 // Visit the fields of this value.
                 match v.layout().fields {
-                    layout::FieldPlacement::Union(fields) => {
+                    layout::FieldsShape::Union(fields) => {
                         self.visit_union(v, fields)?;
                     },
-                    layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
+                    layout::FieldsShape::Arbitrary { ref offsets, .. } => {
                         // FIXME: We collect in a vec because otherwise there are lifetime
                         // errors: Projecting to a field needs access to `ecx`.
                         let fields: Vec<InterpResult<'tcx, Self::V>> =
@@ -220,7 +220,7 @@
                             .collect();
                         self.visit_aggregate(v, fields.into_iter())?;
                     },
-                    layout::FieldPlacement::Array { .. } => {
+                    layout::FieldsShape::Array { .. } => {
                         // Let's get an mplace first.
                         let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
                         // Now we can go over all the fields.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index b51c614..f4cba87 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -183,7 +183,6 @@
 
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _span: Span,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
         _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
@@ -204,7 +203,6 @@
 
     fn call_intrinsic(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _span: Span,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
         _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
@@ -361,7 +359,6 @@
 
         ecx.push_stack_frame(
             Instance::new(def_id, substs),
-            span,
             dummy_body,
             ret.map(Into::into),
             StackPopCleanup::None { cleanup: false },
diff --git a/src/librustc_target/abi/call/mips64.rs b/src/librustc_target/abi/call/mips64.rs
index 285cb5f..81de630 100644
--- a/src/librustc_target/abi/call/mips64.rs
+++ b/src/librustc_target/abi/call/mips64.rs
@@ -49,7 +49,7 @@
         // use of float registers to structures (not unions) containing exactly one or two
         // float fields.
 
-        if let abi::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
+        if let abi::FieldsShape::Arbitrary { .. } = ret.layout.fields {
             if ret.layout.fields.count() == 1 {
                 if let Some(reg) = float_reg(cx, ret, 0) {
                     ret.cast_to(reg);
@@ -88,15 +88,15 @@
     let mut prefix_index = 0;
 
     match arg.layout.fields {
-        abi::FieldPlacement::Array { .. } => {
+        abi::FieldsShape::Array { .. } => {
             // Arrays are passed indirectly
             arg.make_indirect();
             return;
         }
-        abi::FieldPlacement::Union(_) => {
+        abi::FieldsShape::Union(_) => {
             // Unions and are always treated as a series of 64-bit integer chunks
         }
-        abi::FieldPlacement::Arbitrary { .. } => {
+        abi::FieldsShape::Arbitrary { .. } => {
             // Structures are split up into a series of 64-bit integer chunks, but any aligned
             // doubles not part of another aggregate are passed as floats.
             let mut last_offset = Size::ZERO;
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
index 72768c3..b6bfa70 100644
--- a/src/librustc_target/abi/call/mod.rs
+++ b/src/librustc_target/abi/call/mod.rs
@@ -1,4 +1,4 @@
-use crate::abi::{self, Abi, Align, FieldPlacement, Size};
+use crate::abi::{self, Abi, Align, FieldsShape, Size};
 use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
 use crate::spec::{self, HasTargetSpec};
 
@@ -315,7 +315,7 @@
                      start: Size|
                      -> Result<(HomogeneousAggregate, Size), Heterogeneous> {
                         let is_union = match layout.fields {
-                            FieldPlacement::Array { count, .. } => {
+                            FieldsShape::Array { count, .. } => {
                                 assert_eq!(start, Size::ZERO);
 
                                 let result = if count > 0 {
@@ -325,8 +325,8 @@
                                 };
                                 return Ok((result, layout.size));
                             }
-                            FieldPlacement::Union(_) => true,
-                            FieldPlacement::Arbitrary { .. } => false,
+                            FieldsShape::Union(_) => true,
+                            FieldsShape::Arbitrary { .. } => false,
                         };
 
                         let mut result = HomogeneousAggregate::NoData;
diff --git a/src/librustc_target/abi/call/riscv.rs b/src/librustc_target/abi/call/riscv.rs
index a916a53..0eb8816 100644
--- a/src/librustc_target/abi/call/riscv.rs
+++ b/src/librustc_target/abi/call/riscv.rs
@@ -6,7 +6,7 @@
 
 use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
 use crate::abi::{
-    self, Abi, FieldPlacement, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods,
+    self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods,
 };
 use crate::spec::HasTargetSpec;
 
@@ -87,12 +87,12 @@
         },
         Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv),
         Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields {
-            FieldPlacement::Union(_) => {
+            FieldsShape::Union(_) => {
                 if !arg_layout.is_zst() {
                     return Err(CannotUseFpConv);
                 }
             }
-            FieldPlacement::Array { count, .. } => {
+            FieldsShape::Array { count, .. } => {
                 for _ in 0..count {
                     let elem_layout = arg_layout.field(cx, 0);
                     should_use_fp_conv_helper(
@@ -105,7 +105,7 @@
                     )?;
                 }
             }
-            FieldPlacement::Arbitrary { .. } => {
+            FieldsShape::Arbitrary { .. } => {
                 match arg_layout.variants {
                     abi::Variants::Multiple { .. } => return Err(CannotUseFpConv),
                     abi::Variants::Single { .. } => (),
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 3cc7292..f382ef9 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -618,7 +618,7 @@
 
 /// Describes how the fields of a type are located in memory.
 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum FieldPlacement {
+pub enum FieldsShape {
     /// All fields start at no offset. The `usize` is the field count.
     ///
     /// In the case of primitives the number of fields is `0`.
@@ -657,38 +657,38 @@
     },
 }
 
-impl FieldPlacement {
+impl FieldsShape {
     pub fn count(&self) -> usize {
         match *self {
-            FieldPlacement::Union(count) => count,
-            FieldPlacement::Array { count, .. } => {
+            FieldsShape::Union(count) => count,
+            FieldsShape::Array { count, .. } => {
                 let usize_count = count as usize;
                 assert_eq!(usize_count as u64, count);
                 usize_count
             }
-            FieldPlacement::Arbitrary { ref offsets, .. } => offsets.len(),
+            FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
         }
     }
 
     pub fn offset(&self, i: usize) -> Size {
         match *self {
-            FieldPlacement::Union(count) => {
+            FieldsShape::Union(count) => {
                 assert!(i < count, "tried to access field {} of union with {} fields", i, count);
                 Size::ZERO
             }
-            FieldPlacement::Array { stride, count } => {
+            FieldsShape::Array { stride, count } => {
                 let i = u64::try_from(i).unwrap();
                 assert!(i < count);
                 stride * i
             }
-            FieldPlacement::Arbitrary { ref offsets, .. } => offsets[i],
+            FieldsShape::Arbitrary { ref offsets, .. } => offsets[i],
         }
     }
 
     pub fn memory_index(&self, i: usize) -> usize {
         match *self {
-            FieldPlacement::Union(_) | FieldPlacement::Array { .. } => i,
-            FieldPlacement::Arbitrary { ref memory_index, .. } => {
+            FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
+            FieldsShape::Arbitrary { ref memory_index, .. } => {
                 let r = memory_index[i];
                 assert_eq!(r as usize as u32, r);
                 r as usize
@@ -704,7 +704,7 @@
         let use_small = self.count() <= inverse_small.len();
 
         // We have to write this logic twice in order to keep the array small.
-        if let FieldPlacement::Arbitrary { ref memory_index, .. } = *self {
+        if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
             if use_small {
                 for i in 0..self.count() {
                     inverse_small[memory_index[i] as usize] = i as u8;
@@ -718,8 +718,8 @@
         }
 
         (0..self.count()).map(move |i| match *self {
-            FieldPlacement::Union(_) | FieldPlacement::Array { .. } => i,
-            FieldPlacement::Arbitrary { .. } => {
+            FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
+            FieldsShape::Arbitrary { .. } => {
                 if use_small {
                     inverse_small[i] as usize
                 } else {
@@ -888,7 +888,7 @@
 pub struct Layout {
     /// Says where the fields are located within the layout.
     /// Primitives and uninhabited enums appear as unions without fields.
-    pub fields: FieldPlacement,
+    pub fields: FieldsShape,
 
     /// Encodes information about multi-variant layouts.
     /// Even with `Multiple` variants, a layout still has its own fields! Those are then
@@ -923,7 +923,7 @@
         let align = scalar.value.align(cx);
         Layout {
             variants: Variants::Single { index: VariantIdx::new(0) },
-            fields: FieldPlacement::Union(0),
+            fields: FieldsShape::Union(0),
             abi: Abi::Scalar(scalar),
             largest_niche,
             size,
diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs
index 3ef44a1..5f98850 100644
--- a/src/librustc_trait_selection/traits/mod.rs
+++ b/src/librustc_trait_selection/traits/mod.rs
@@ -54,7 +54,6 @@
 };
 pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
 pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
-pub use self::specialize::find_associated_item;
 pub use self::specialize::specialization_graph::FutureCompatOverlapError;
 pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
@@ -64,8 +63,7 @@
 pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
 pub use self::util::{expand_trait_aliases, TraitAliasExpander};
 pub use self::util::{
-    get_vtable_index_of_object_method, impl_is_default, impl_item_is_final,
-    predicate_for_trait_def, upcast_choices,
+    get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
 };
 pub use self::util::{
     supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 2eb63b8..aae0d46 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -1015,49 +1015,21 @@
                     assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
                         .map_err(|ErrorReported| ())?;
 
-                let is_default = if node_item.node.is_from_trait() {
-                    // If true, the impl inherited a `type Foo = Bar`
-                    // given in the trait, which is implicitly default.
-                    // Otherwise, the impl did not specify `type` and
-                    // neither did the trait:
-                    //
-                    // ```rust
-                    // trait Foo { type T; }
-                    // impl Foo for Bar { }
-                    // ```
-                    //
-                    // This is an error, but it will be
-                    // reported in `check_impl_items_against_trait`.
-                    // We accept it here but will flag it as
-                    // an error when we confirm the candidate
-                    // (which will ultimately lead to `normalize_to_error`
-                    // being invoked).
-                    false
+                if node_item.is_final() {
+                    // Non-specializable items are always projectable.
+                    true
                 } else {
-                    // If we're looking at a trait *impl*, the item is
-                    // specializable if the impl or the item are marked
-                    // `default`.
-                    node_item.item.defaultness.is_default()
-                        || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id())
-                };
-
-                match is_default {
-                    // Non-specializable items are always projectable
-                    false => true,
-
                     // Only reveal a specializable default if we're past type-checking
                     // and the obligation is monomorphic, otherwise passes such as
                     // transmute checking and polymorphic MIR optimizations could
                     // get a result which isn't correct for all monomorphizations.
-                    true if obligation.param_env.reveal == Reveal::All => {
+                    if obligation.param_env.reveal == Reveal::All {
                         // NOTE(eddyb) inference variables can resolve to parameters, so
                         // assume `poly_trait_ref` isn't monomorphic, if it contains any.
                         let poly_trait_ref =
                             selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
                         !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst()
-                    }
-
-                    true => {
+                    } else {
                         debug!(
                             "assemble_candidates_from_impls: not eligible due to default: \
                              assoc_ty={} predicate={}",
@@ -1422,7 +1394,8 @@
         return Progress { ty: tcx.types.err, obligations: nested };
     }
     let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
-    let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
+    let substs =
+        translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
     let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind {
         let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
         tcx.mk_opaque(assoc_ty.item.def_id, item_substs)
@@ -1447,7 +1420,7 @@
     selcx: &SelectionContext<'_, '_>,
     impl_def_id: DefId,
     assoc_ty_def_id: DefId,
-) -> Result<specialization_graph::NodeItem<ty::AssocItem>, ErrorReported> {
+) -> Result<specialization_graph::LeafDef, ErrorReported> {
     let tcx = selcx.tcx();
     let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
     let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
@@ -1464,9 +1437,10 @@
         if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy)
             && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
         {
-            return Ok(specialization_graph::NodeItem {
-                node: specialization_graph::Node::Impl(impl_def_id),
+            return Ok(specialization_graph::LeafDef {
                 item: *item,
+                defining_node: impl_node,
+                finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
             });
         }
     }
diff --git a/src/librustc_trait_selection/traits/specialize/mod.rs b/src/librustc_trait_selection/traits/specialize/mod.rs
index edf02d7..fabd8c8 100644
--- a/src/librustc_trait_selection/traits/specialize/mod.rs
+++ b/src/librustc_trait_selection/traits/specialize/mod.rs
@@ -20,7 +20,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
 use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
 use rustc_span::DUMMY_SP;
@@ -112,48 +112,6 @@
     source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
 }
 
-/// Given a selected impl described by `impl_data`, returns the
-/// definition and substitutions for the method with the name `name`
-/// the kind `kind`, and trait method substitutions `substs`, in
-/// that impl, a less specialized impl, or the trait default,
-/// whichever applies.
-pub fn find_associated_item<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    item: &ty::AssocItem,
-    substs: SubstsRef<'tcx>,
-    impl_data: &super::VtableImplData<'tcx, ()>,
-) -> (DefId, SubstsRef<'tcx>) {
-    debug!("find_associated_item({:?}, {:?}, {:?}, {:?})", param_env, item, substs, impl_data);
-    assert!(!substs.needs_infer());
-
-    let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
-    let trait_def = tcx.trait_def(trait_def_id);
-
-    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_data.impl_def_id) {
-        match ancestors.leaf_def(tcx, item.ident, item.kind) {
-            Some(node_item) => {
-                let substs = tcx.infer_ctxt().enter(|infcx| {
-                    let param_env = param_env.with_reveal_all();
-                    let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
-                    let substs = translate_substs(
-                        &infcx,
-                        param_env,
-                        impl_data.impl_def_id,
-                        substs,
-                        node_item.node,
-                    );
-                    infcx.tcx.erase_regions(&substs)
-                });
-                (node_item.item.def_id, substs)
-            }
-            None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id),
-        }
-    } else {
-        (item.def_id, substs)
-    }
-}
-
 /// Is `impl1` a specialization of `impl2`?
 ///
 /// Specialization is determined by the sets of types to which the impls apply;
diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs
index 6eeac2f..6348673 100644
--- a/src/librustc_trait_selection/traits/util.rs
+++ b/src/librustc_trait_selection/traits/util.rs
@@ -4,7 +4,6 @@
 use smallvec::SmallVec;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
@@ -651,22 +650,8 @@
     ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
 }
 
-pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool {
-    match tcx.hir().as_local_hir_id(node_item_def_id) {
-        Some(hir_id) => {
-            let item = tcx.hir().expect_item(hir_id);
-            if let hir::ItemKind::Impl { defaultness, .. } = item.kind {
-                defaultness.is_default()
-            } else {
-                false
-            }
-        }
-        None => tcx.impl_defaultness(node_item_def_id).is_default(),
-    }
-}
-
 pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
-    assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id())
+    assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final()
 }
 
 pub enum TupleArgumentsFlag {
diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs
index 447c49e..47c4b1c 100644
--- a/src/librustc_ty/instance.rs
+++ b/src/librustc_ty/instance.rs
@@ -1,9 +1,11 @@
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
 use rustc_span::sym;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
+use traits::{translate_substs, Reveal};
 
 use log::debug;
 
@@ -82,21 +84,50 @@
     // the actual function:
     match vtbl {
         traits::VtableImpl(impl_data) => {
-            let (def_id, substs) =
-                traits::find_associated_item(tcx, param_env, trait_item, rcvr_substs, &impl_data);
+            debug!(
+                "resolving VtableImpl: {:?}, {:?}, {:?}, {:?}",
+                param_env, trait_item, rcvr_substs, impl_data
+            );
+            assert!(!rcvr_substs.needs_infer());
+            assert!(!trait_ref.needs_infer());
 
-            let resolved_item = tcx.associated_item(def_id);
+            let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
+            let trait_def = tcx.trait_def(trait_def_id);
+            let leaf_def = trait_def
+                .ancestors(tcx, impl_data.impl_def_id)
+                .ok()?
+                .leaf_def(tcx, trait_item.ident, trait_item.kind)
+                .unwrap_or_else(|| {
+                    bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
+                });
+            let def_id = leaf_def.item.def_id;
+
+            let substs = tcx.infer_ctxt().enter(|infcx| {
+                let param_env = param_env.with_reveal_all();
+                let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
+                let substs = translate_substs(
+                    &infcx,
+                    param_env,
+                    impl_data.impl_def_id,
+                    substs,
+                    leaf_def.defining_node,
+                );
+                infcx.tcx.erase_regions(&substs)
+            });
 
             // Since this is a trait item, we need to see if the item is either a trait default item
             // or a specialization because we can't resolve those unless we can `Reveal::All`.
             // NOTE: This should be kept in sync with the similar code in
             // `rustc_middle::traits::project::assemble_candidates_from_impls()`.
-            let eligible = if !resolved_item.defaultness.is_default() {
+            let eligible = if leaf_def.is_final() {
+                // Non-specializable items are always projectable.
                 true
-            } else if param_env.reveal == traits::Reveal::All {
-                !trait_ref.needs_subst()
             } else {
-                false
+                // Only reveal a specializable default if we're past type-checking
+                // and the obligation is monomorphic, otherwise passes such as
+                // transmute checking and polymorphic MIR optimizations could
+                // get a result which isn't correct for all monomorphizations.
+                if param_env.reveal == Reveal::All { !trait_ref.needs_subst() } else { false }
             };
 
             if !eligible {
diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs
index 9d28447..aefe61f 100644
--- a/src/librustc_ty/ty.rs
+++ b/src/librustc_ty/ty.rs
@@ -165,6 +165,16 @@
     )
 }
 
+fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
+    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+    let item = tcx.hir().expect_item(hir_id);
+    if let hir::ItemKind::Impl { defaultness, .. } = item.kind {
+        defaultness
+    } else {
+        bug!("`impl_defaultness` called on {:?}", item);
+    }
+}
+
 /// Calculates the `Sized` constraint.
 ///
 /// In fact, there are only a few options for the types in the constraint:
@@ -371,6 +381,7 @@
         crate_hash,
         instance_def_size_estimate,
         issue33140_self_ty,
+        impl_defaultness,
         ..*providers
     };
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 6249e1d..3823efe 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1942,7 +1942,7 @@
             // grandparent. In that case, if parent is a `default impl`, inherited items use the
             // "defaultness" from the grandparent, else they are final.
             None => {
-                if traits::impl_is_default(tcx, parent_impl.def_id()) {
+                if tcx.impl_defaultness(parent_impl.def_id()).is_default() {
                     None
                 } else {
                     Some(Err(parent_impl.def_id()))
@@ -2114,10 +2114,10 @@
         for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
             let is_implemented = ancestors
                 .leaf_def(tcx, trait_item.ident, trait_item.kind)
-                .map(|node_item| !node_item.node.is_from_trait())
+                .map(|node_item| !node_item.defining_node.is_from_trait())
                 .unwrap_or(false);
 
-            if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
+            if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
                 if !trait_item.defaultness.has_value() {
                     missing_items.push(*trait_item);
                 }
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr
index cede356..f1e9192 100644
--- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr
@@ -5,7 +5,8 @@
    |              ^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              transmuting to uninhabited type
-   |              inside call to `foo` at $DIR/validate_uninhabited_zsts.rs:14:26
+   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:5:14
+   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:14:26
 ...
 LL | const FOO: [Empty; 3] = [foo(); 3];
    | -----------------------------------
diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
index c7e9021..8ed1431 100644
--- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
+++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
@@ -17,7 +17,8 @@
    |     ^^^^^^^
    |     |
    |     calling a function with ABI C using caller ABI Rust
-   |     inside call to `call_rust_fn` at $DIR/abi-mismatch.rs:13:17
+   |     inside `call_rust_fn` at $DIR/abi-mismatch.rs:9:5
+   |     inside `VAL` at $DIR/abi-mismatch.rs:13:17
 ...
 LL | const VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) });
    | --------------------------------------------------------------------------------------
diff --git a/src/test/ui/consts/miri_unleashed/drop.stderr b/src/test/ui/consts/miri_unleashed/drop.stderr
index 2439d52..5d560fa 100644
--- a/src/test/ui/consts/miri_unleashed/drop.stderr
+++ b/src/test/ui/consts/miri_unleashed/drop.stderr
@@ -12,12 +12,15 @@
 LL | |     // real drop glue by the compiler.
 LL | |     drop_in_place(to_drop)
 LL | | }
-   | |_^ calling non-const function `<std::vec::Vec<i32> as std::ops::Drop>::drop`
+   | | ^
+   | | |
+   | |_calling non-const function `<std::vec::Vec<i32> as std::ops::Drop>::drop`
+   |   inside `std::intrinsics::drop_in_place::<std::vec::Vec<i32>> - shim(Some(std::vec::Vec<i32>))` at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
    | 
   ::: $DIR/drop.rs:23:1
    |
 LL |   };
-   |   - inside call to `std::intrinsics::drop_in_place::<std::vec::Vec<i32>> - shim(Some(std::vec::Vec<i32>))` at $DIR/drop.rs:23:1
+   |   - inside `TEST_BAD` at $DIR/drop.rs:23:1
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr
index 2175307..f1a183b 100644
--- a/src/test/ui/consts/offset_from_ub.stderr
+++ b/src/test/ui/consts/offset_from_ub.stderr
@@ -5,7 +5,8 @@
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           ptr_offset_from cannot compute offset of pointers into different allocations.
-   |           inside call to `std::ptr::const_ptr::<impl *const Struct>::offset_from` at $DIR/offset_from_ub.rs:22:27
+   |           inside `std::ptr::const_ptr::<impl *const Struct>::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |           inside `DIFFERENT_ALLOC` at $DIR/offset_from_ub.rs:22:27
    | 
   ::: $DIR/offset_from_ub.rs:16:1
    |
@@ -27,7 +28,8 @@
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           unable to turn bytes into a pointer
-   |           inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:28:14
+   |           inside `std::ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |           inside `NOT_PTR` at $DIR/offset_from_ub.rs:28:14
    | 
   ::: $DIR/offset_from_ub.rs:26:1
    |
@@ -44,7 +46,8 @@
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           exact_div: 1isize cannot be divided by 2isize without remainder
-   |           inside call to `std::ptr::const_ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:36:14
+   |           inside `std::ptr::const_ptr::<impl *const u16>::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |           inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:36:14
    | 
   ::: $DIR/offset_from_ub.rs:31:1
    |
@@ -64,7 +67,8 @@
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           invalid use of NULL pointer
-   |           inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:42:14
+   |           inside `std::ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |           inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:42:14
    | 
   ::: $DIR/offset_from_ub.rs:39:1
    |
@@ -82,7 +86,8 @@
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           unable to turn bytes into a pointer
-   |           inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:49:14
+   |           inside `std::ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |           inside `DIFFERENT_INT` at $DIR/offset_from_ub.rs:49:14
    | 
   ::: $DIR/offset_from_ub.rs:45:1
    |
diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr
index 1f3e2cf..ca23238 100644
--- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr
+++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr
@@ -4,76 +4,140 @@
 LL |     hint_unreachable()
    |     ------------------
    |     |
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5
 ...
 LL |     fake_type()
    |     ^^^^^^^^^^^
    |     |
    |     reached the configured maximum number of stack frames
-   |     inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
 
 error: any use of this value will cause an error
   --> $DIR/uninhabited-const-issue-61744.rs:12:36
diff --git a/src/test/ui/specialization/issue-70442.rs b/src/test/ui/specialization/issue-70442.rs
new file mode 100644
index 0000000..4371dd2
--- /dev/null
+++ b/src/test/ui/specialization/issue-70442.rs
@@ -0,0 +1,23 @@
+#![feature(specialization)]
+
+// check-pass
+
+trait Trait {
+    type Assoc;
+}
+
+impl<T> Trait for T {
+    default type Assoc = bool;
+}
+
+// This impl inherits the `Assoc` definition from above and "locks it in", or finalizes it, making
+// child impls unable to further specialize it. However, since the specialization graph didn't
+// correctly track this, we would refuse to project `Assoc` from this impl, even though that should
+// happen for items that are final.
+impl Trait for () {}
+
+fn foo<X: Trait<Assoc=bool>>() {}
+
+fn main() {
+    foo::<()>();  // `<() as Trait>::Assoc` is normalized to `bool` correctly
+}
diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs
index cf00cb1..6968822 100644
--- a/src/tools/cargotest/main.rs
+++ b/src/tools/cargotest/main.rs
@@ -58,13 +58,6 @@
         // This takes much less time to build than all of Servo and supports stable Rust.
         packages: &["selectors"],
     },
-    Test {
-        name: "webrender",
-        repo: "https://github.com/servo/webrender",
-        sha: "a3d6e6894c5a601fa547c6273eb963ca1321c2bb",
-        lock: None,
-        packages: &[],
-    },
 ];
 
 fn main() {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 0ee016f..8a291a3 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -180,29 +180,25 @@
 }
 
 fn print_diff(expected: &str, actual: &str, context_size: usize) {
-    write_diff(expected, actual, context_size, std::io::stdout());
-}
-
-fn write_diff(expected: &str, actual: &str, context_size: usize, mut dest: impl io::Write) {
     let diff_results = make_diff(expected, actual, context_size);
     for result in diff_results {
         let mut line_number = result.line_number;
         for line in result.lines {
             match line {
                 DiffLine::Expected(e) => {
-                    writeln!(dest, "-\t{}", e).unwrap();
+                    println!("-\t{}", e);
                     line_number += 1;
                 }
                 DiffLine::Context(c) => {
-                    writeln!(dest, "{}\t{}", line_number, c).unwrap();
+                    println!("{}\t{}", line_number, c);
                     line_number += 1;
                 }
                 DiffLine::Resulting(r) => {
-                    writeln!(dest, "+\t{}", r).unwrap();
+                    println!("+\t{}", r);
                 }
             }
         }
-        writeln!(dest).unwrap();
+        println!();
     }
 }