about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs89
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs4
-rw-r--r--compiler/rustc_data_structures/src/graph/mod.rs9
-rw-r--r--compiler/rustc_driver/src/lib.rs3
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0530.md53
-rw-r--r--compiler/rustc_errors/src/emitter.rs120
-rw-r--r--compiler/rustc_errors/src/lib.rs83
-rw-r--r--compiler/rustc_errors/src/snippet.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs12
-rw-r--r--compiler/rustc_feature/src/removed.rs5
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs44
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs47
-rw-r--r--compiler/rustc_interface/src/passes.rs3
-rw-r--r--compiler/rustc_lexer/src/unescape.rs17
-rw-r--r--compiler/rustc_lexer/src/unescape/tests.rs5
-rw-r--r--compiler/rustc_metadata/src/locator.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs3
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs164
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs5
-rw-r--r--compiler/rustc_plugin_impl/src/build.rs57
-rw-r--r--compiler/rustc_plugin_impl/src/lib.rs1
-rw-r--r--compiler/rustc_plugin_impl/src/load.rs17
-rw-r--r--compiler/rustc_session/src/session.rs6
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs11
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs4
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs234
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs13
-rw-r--r--compiler/rustc_typeck/src/check/check.rs70
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs17
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs51
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs20
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs12
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs32
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs5
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs3
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs7
43 files changed, 670 insertions, 619 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 89b59e5f00f..6dc459ea402 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -375,14 +375,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Fn(..) => {
-                if self.sess.contains_name(&i.attrs[..], sym::plugin_registrar) {
-                    gate_feature_post!(
-                        &self,
-                        plugin_registrar,
-                        i.span,
-                        "compiler plugins are experimental and possibly buggy"
-                    );
-                }
                 if self.sess.contains_name(&i.attrs[..], sym::start) {
                     gate_feature_post!(
                         &self,
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 685f222e802..5d56c93f835 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -24,6 +24,7 @@ use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx};
 use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
+use smallvec::SmallVec;
 
 use std::cell::{Cell, RefCell};
 use std::ffi::CStr;
@@ -74,8 +75,12 @@ pub struct CodegenCx<'ll, 'tcx> {
     /// See <https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details
     pub used_statics: RefCell<Vec<&'ll Value>>,
 
-    pub lltypes: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), &'ll Type>>,
+    /// Mapping of non-scalar types to llvm types and field remapping if needed.
+    pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), TypeLowering<'ll>>>,
+
+    /// Mapping of scalar types to llvm types.
     pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'ll Type>>,
+
     pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
     pub isize_ty: &'ll Type,
 
@@ -92,6 +97,15 @@ pub struct CodegenCx<'ll, 'tcx> {
     local_gen_sym_counter: Cell<usize>,
 }
 
+pub struct TypeLowering<'ll> {
+    /// Associated LLVM type
+    pub lltype: &'ll Type,
+
+    /// If padding is used the slice maps fields from source order
+    /// to llvm order.
+    pub field_remapping: Option<SmallVec<[u32; 4]>>,
+}
+
 fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
     match tls_model {
         TlsModel::GeneralDynamic => llvm::ThreadLocalMode::GeneralDynamic,
@@ -304,7 +318,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             const_globals: Default::default(),
             statics_to_rauw: RefCell::new(Vec::new()),
             used_statics: RefCell::new(Vec::new()),
-            lltypes: Default::default(),
+            type_lowering: Default::default(),
             scalar_lltypes: Default::default(),
             pointee_infos: Default::default(),
             isize_ty,
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 52ae56b89b3..c7f4287e28e 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -266,7 +266,7 @@ impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         layout.is_llvm_scalar_pair()
     }
     fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
-        layout.llvm_field_index(index)
+        layout.llvm_field_index(self, index)
     }
     fn scalar_pair_element_backend_type(
         &self,
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 0876907e119..85efe3e6483 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -1,5 +1,6 @@
 use crate::abi::FnAbi;
 use crate::common::*;
+use crate::context::TypeLowering;
 use crate::type_::Type;
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
@@ -9,6 +10,7 @@ use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAndLayoutMethods, Variants};
+use smallvec::{smallvec, SmallVec};
 use tracing::debug;
 
 use std::fmt::Write;
@@ -17,6 +19,7 @@ fn uncached_llvm_type<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
     layout: TyAndLayout<'tcx>,
     defer: &mut Option<(&'a Type, TyAndLayout<'tcx>)>,
+    field_remapping: &mut Option<SmallVec<[u32; 4]>>,
 ) -> &'a Type {
     match layout.abi {
         Abi::Scalar(_) => bug!("handled elsewhere"),
@@ -75,7 +78,8 @@ fn uncached_llvm_type<'a, 'tcx>(
         FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).llvm_type(cx), count),
         FieldsShape::Arbitrary { .. } => match name {
             None => {
-                let (llfields, packed) = struct_llfields(cx, layout);
+                let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout);
+                *field_remapping = new_field_remapping;
                 cx.type_struct(&llfields, packed)
             }
             Some(ref name) => {
@@ -90,7 +94,7 @@ fn uncached_llvm_type<'a, 'tcx>(
 fn struct_llfields<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
     layout: TyAndLayout<'tcx>,
-) -> (Vec<&'a Type>, bool) {
+) -> (Vec<&'a Type>, bool, Option<SmallVec<[u32; 4]>>) {
     debug!("struct_llfields: {:#?}", layout);
     let field_count = layout.fields.count();
 
@@ -98,6 +102,7 @@ fn struct_llfields<'a, 'tcx>(
     let mut offset = Size::ZERO;
     let mut prev_effective_align = layout.align.abi;
     let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
+    let mut field_remapping = smallvec![0; field_count];
     for i in layout.fields.index_by_increasing_offset() {
         let target_offset = layout.fields.offset(i as usize);
         let field = layout.field(cx, i);
@@ -116,33 +121,37 @@ fn struct_llfields<'a, 'tcx>(
         );
         assert!(target_offset >= offset);
         let padding = target_offset - offset;
-        let padding_align = prev_effective_align.min(effective_field_align);
-        assert_eq!(offset.align_to(padding_align) + padding, target_offset);
-        result.push(cx.type_padding_filler(padding, padding_align));
-        debug!("    padding before: {:?}", padding);
-
+        if padding != Size::ZERO {
+            let padding_align = prev_effective_align.min(effective_field_align);
+            assert_eq!(offset.align_to(padding_align) + padding, target_offset);
+            result.push(cx.type_padding_filler(padding, padding_align));
+            debug!("    padding before: {:?}", padding);
+        }
+        field_remapping[i] = result.len() as u32;
         result.push(field.llvm_type(cx));
         offset = target_offset + field.size;
         prev_effective_align = effective_field_align;
     }
+    let padding_used = result.len() > field_count;
     if !layout.is_unsized() && field_count > 0 {
         if offset > layout.size {
             bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
         }
         let padding = layout.size - offset;
-        let padding_align = prev_effective_align;
-        assert_eq!(offset.align_to(padding_align) + padding, layout.size);
-        debug!(
-            "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
-            padding, offset, layout.size
-        );
-        result.push(cx.type_padding_filler(padding, padding_align));
-        assert_eq!(result.len(), 1 + field_count * 2);
+        if padding != Size::ZERO {
+            let padding_align = prev_effective_align;
+            assert_eq!(offset.align_to(padding_align) + padding, layout.size);
+            debug!(
+                "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
+                padding, offset, layout.size
+            );
+            result.push(cx.type_padding_filler(padding, padding_align));
+        }
     } else {
         debug!("struct_llfields: offset: {:?} stride: {:?}", offset, layout.size);
     }
-
-    (result, packed)
+    let field_remapping = if padding_used { Some(field_remapping) } else { None };
+    (result, packed, field_remapping)
 }
 
 impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
@@ -177,7 +186,7 @@ pub trait LayoutLlvmExt<'tcx> {
         index: usize,
         immediate: bool,
     ) -> &'a Type;
-    fn llvm_field_index(&self, index: usize) -> u64;
+    fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64;
     fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo>;
 }
 
@@ -234,8 +243,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
             Variants::Single { index } => Some(index),
             _ => None,
         };
-        if let Some(&llty) = cx.lltypes.borrow().get(&(self.ty, variant_index)) {
-            return llty;
+        if let Some(ref llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
+            return llty.lltype;
         }
 
         debug!("llvm_type({:#?})", self);
@@ -247,6 +256,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
         let normal_ty = cx.tcx.erase_regions(self.ty);
 
         let mut defer = None;
+        let mut field_remapping = None;
         let llty = if self.ty != normal_ty {
             let mut layout = cx.layout_of(normal_ty);
             if let Some(v) = variant_index {
@@ -254,17 +264,24 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
             }
             layout.llvm_type(cx)
         } else {
-            uncached_llvm_type(cx, *self, &mut defer)
+            uncached_llvm_type(cx, *self, &mut defer, &mut field_remapping)
         };
         debug!("--> mapped {:#?} to llty={:?}", self, llty);
 
-        cx.lltypes.borrow_mut().insert((self.ty, variant_index), llty);
+        cx.type_lowering.borrow_mut().insert(
+            (self.ty, variant_index),
+            TypeLowering { lltype: llty, field_remapping: field_remapping },
+        );
 
         if let Some((llty, layout)) = defer {
-            let (llfields, packed) = struct_llfields(cx, layout);
-            cx.set_struct_body(llty, &llfields, packed)
+            let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout);
+            cx.set_struct_body(llty, &llfields, packed);
+            cx.type_lowering
+                .borrow_mut()
+                .get_mut(&(self.ty, variant_index))
+                .unwrap()
+                .field_remapping = new_field_remapping;
         }
-
         llty
     }
 
@@ -340,7 +357,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
         self.scalar_llvm_type_at(cx, scalar, offset)
     }
 
-    fn llvm_field_index(&self, index: usize) -> u64 {
+    fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64 {
         match self.abi {
             Abi::Scalar(_) | Abi::ScalarPair(..) => {
                 bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self)
@@ -354,7 +371,25 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
 
             FieldsShape::Array { .. } => index as u64,
 
-            FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2,
+            FieldsShape::Arbitrary { .. } => {
+                let variant_index = match self.variants {
+                    Variants::Single { index } => Some(index),
+                    _ => None,
+                };
+
+                // Look up llvm field if indexes do not match memory order due to padding. If
+                // `field_remapping` is `None` no padding was used and the llvm field index
+                // matches the memory index.
+                match cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
+                    Some(TypeLowering { field_remapping: Some(ref remap), .. }) => {
+                        remap[index] as u64
+                    }
+                    Some(_) => self.fields.memory_index(index) as u64,
+                    None => {
+                        bug!("TyAndLayout::llvm_field_index({:?}): type info not found", self)
+                    }
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index c9fb09570c3..2208ec37a42 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -98,7 +98,8 @@ fn emit_aapcs_va_arg(
     // Implementation of the AAPCS64 calling convention for va_args see
     // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
     let va_list_addr = list.immediate();
-    let va_list_ty = list.deref(bx.cx).layout.llvm_type(bx);
+    let va_list_layout = list.deref(bx.cx).layout;
+    let va_list_ty = va_list_layout.llvm_type(bx);
     let layout = bx.cx.layout_of(target_ty);
 
     let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg");
@@ -110,13 +111,15 @@ fn emit_aapcs_va_arg(
 
     let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
     let (reg_off, reg_top_index, slot_size) = if gr_type {
-        let gr_offs = bx.struct_gep(va_list_ty, va_list_addr, 7);
+        let gr_offs =
+            bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 3));
         let nreg = (layout.size.bytes() + 7) / 8;
-        (gr_offs, 3, nreg * 8)
+        (gr_offs, va_list_layout.llvm_field_index(bx.cx, 1), nreg * 8)
     } else {
-        let vr_off = bx.struct_gep(va_list_ty, va_list_addr, 9);
+        let vr_off =
+            bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 4));
         let nreg = (layout.size.bytes() + 15) / 16;
-        (vr_off, 5, nreg * 16)
+        (vr_off, va_list_layout.llvm_field_index(bx.cx, 2), nreg * 16)
     };
 
     // if the offset >= 0 then the value will be on the stack
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 4ef21449d21..4a7090b31b4 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -137,10 +137,6 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
         reachable_non_generics.insert(id.to_def_id(), SymbolExportLevel::C);
     }
 
-    if let Some(id) = tcx.plugin_registrar_fn(()) {
-        reachable_non_generics.insert(id.to_def_id(), SymbolExportLevel::C);
-    }
-
     reachable_non_generics
 }
 
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index e0903e43241..dff22855629 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -60,18 +60,13 @@ pub trait WithStartNode: DirectedGraph {
 }
 
 pub trait ControlFlowGraph:
-    DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes
+    DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
 {
     // convenient trait
 }
 
 impl<T> ControlFlowGraph for T where
-    T: DirectedGraph
-        + WithStartNode
-        + WithPredecessors
-        + WithStartNode
-        + WithSuccessors
-        + WithNumNodes
+    T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
 {
 }
 
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 84dd69ebd96..fcc70b2e4c5 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1287,9 +1287,6 @@ pub fn init_env_logger(env: &str) {
         .with_indent_lines(true)
         .with_ansi(color_logs)
         .with_targets(true)
-        .with_wraparound(10)
-        .with_verbose_exit(true)
-        .with_verbose_entry(true)
         .with_indent_amount(2);
     #[cfg(parallel_compiler)]
     let layer = layer.with_thread_ids(true).with_thread_names(true);
diff --git a/compiler/rustc_error_codes/src/error_codes/E0530.md b/compiler/rustc_error_codes/src/error_codes/E0530.md
index 502f674fc1d..60fa711cbed 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0530.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0530.md
@@ -1,32 +1,57 @@
 A binding shadowed something it shouldn't.
 
-Erroneous code example:
+A match arm or a variable has a name that is already used by
+something else, e.g.
+
+* struct name
+* enum variant
+* static
+* associated constant
+
+This error may also happen when an enum variant *with fields* is used
+in a pattern, but without its fields.
+
+```compile_fail
+enum Enum {
+    WithField(i32)
+}
+
+use Enum::*;
+match WithField(1) {
+    WithField => {} // error: missing (_)
+}
+```
+
+Match bindings cannot shadow statics:
 
 ```compile_fail,E0530
 static TEST: i32 = 0;
 
-let r: (i32, i32) = (0, 0);
+let r = 123;
 match r {
-    TEST => {} // error: match bindings cannot shadow statics
+    TEST => {} // error: name of a static
 }
 ```
 
-To fix this error, just change the binding's name in order to avoid shadowing
-one of the following:
+Fixed examples:
 
-* struct name
-* struct/enum variant
-* static
-* const
-* associated const
+```
+static TEST: i32 = 0;
 
-Fixed example:
+let r = 123;
+match r {
+    some_value => {} // ok!
+}
+```
+
+or
 
 ```
-static TEST: i32 = 0;
+const TEST: i32 = 0; // const, not static
 
-let r: (i32, i32) = (0, 0);
+let r = 123;
 match r {
-    something => {} // ok!
+    TEST => {} // const is ok!
+    other_values => {}
 }
 ```
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 050f3ae5833..07c864c93a1 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -14,7 +14,10 @@ use rustc_span::{MultiSpan, SourceFile, Span};
 
 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
 use crate::styled_buffer::StyledBuffer;
-use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle};
+use crate::{
+    CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SubstitutionHighlight,
+    SuggestionStyle,
+};
 
 use rustc_lint_defs::pluralize;
 
@@ -1590,8 +1593,11 @@ impl EmitterWriter {
         );
 
         let mut row_num = 2;
+        draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
         let mut notice_capitalization = false;
-        for (complete, parts, only_capitalization) in suggestions.iter().take(MAX_SUGGESTIONS) {
+        for (complete, parts, highlights, only_capitalization) in
+            suggestions.iter().take(MAX_SUGGESTIONS)
+        {
             notice_capitalization |= only_capitalization;
             // Only show underline if the suggestion spans a single line and doesn't cover the
             // entirety of the code output. If you have multiple replacements in the same line
@@ -1599,16 +1605,26 @@ impl EmitterWriter {
             let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim())
                 && complete.lines().count() == 1;
 
-            let lines = sm
+            let has_deletion = parts.iter().any(|p| p.is_deletion());
+            let is_multiline = complete.lines().count() > 1;
+
+            let show_diff = has_deletion && !is_multiline;
+
+            if show_diff {
+                row_num += 1;
+            }
+
+            let file_lines = sm
                 .span_to_lines(parts[0].span)
                 .expect("span_to_lines failed when emitting suggestion");
 
-            assert!(!lines.lines.is_empty() || parts[0].span.is_dummy());
+            assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
 
             let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
             draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
             let mut lines = complete.lines();
-            for (line_pos, line) in lines.by_ref().take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
+            for (line_pos, (line, parts)) in
+                lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
             {
                 // Print the span column to avoid confusion
                 buffer.puts(
@@ -1617,9 +1633,60 @@ impl EmitterWriter {
                     &self.maybe_anonymized(line_start + line_pos),
                     Style::LineNumber,
                 );
+                if show_diff {
+                    // Add the line number for both addition and removal to drive the point home.
+                    //
+                    // N - fn foo<A: T>(bar: A) {
+                    // N + fn foo(bar: impl T) {
+                    buffer.puts(
+                        row_num - 1,
+                        0,
+                        &self.maybe_anonymized(line_start + line_pos),
+                        Style::LineNumber,
+                    );
+                    buffer.puts(row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+                    buffer.puts(
+                        row_num - 1,
+                        max_line_num_len + 3,
+                        &replace_tabs(
+                            &*file_lines
+                                .file
+                                .get_line(file_lines.lines[line_pos].line_index)
+                                .unwrap(),
+                        ),
+                        Style::NoStyle,
+                    );
+                    buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
+                } else if is_multiline {
+                    match &parts[..] {
+                        [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
+                            buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
+                        }
+                        [] => {
+                            draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+                        }
+                        _ => {
+                            buffer.puts(row_num, max_line_num_len + 1, "~ ", Style::Addition);
+                        }
+                    }
+                } else {
+                    draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+                }
+
                 // print the suggestion
-                draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
                 buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
+
+                if is_multiline {
+                    for SubstitutionHighlight { start, end } in parts {
+                        buffer.set_style_range(
+                            row_num,
+                            max_line_num_len + 3 + start,
+                            max_line_num_len + 3 + end,
+                            Style::Addition,
+                            true,
+                        );
+                    }
+                }
                 row_num += 1;
             }
 
@@ -1654,25 +1721,36 @@ impl EmitterWriter {
                     let underline_start = (span_start_pos + start) as isize + offset;
                     let underline_end = (span_start_pos + start + sub_len) as isize + offset;
                     assert!(underline_start >= 0 && underline_end >= 0);
+                    let padding: usize = max_line_num_len + 3;
                     for p in underline_start..underline_end {
-                        buffer.putc(
-                            row_num,
-                            ((max_line_num_len + 3) as isize + p) as usize,
-                            '^',
-                            Style::UnderlinePrimary,
+                        // Colorize addition/replacements with green.
+                        buffer.set_style(
+                            row_num - 1,
+                            (padding as isize + p) as usize,
+                            Style::Addition,
+                            true,
                         );
-                    }
-                    // underline removals too
-                    if underline_start == underline_end {
-                        for p in underline_start - 1..underline_start + 1 {
+                        if !show_diff {
+                            // If this is a replacement, underline with `^`, if this is an addition
+                            // underline with `+`.
                             buffer.putc(
                                 row_num,
-                                ((max_line_num_len + 3) as isize + p) as usize,
-                                '-',
-                                Style::UnderlineSecondary,
+                                (padding as isize + p) as usize,
+                                if part.is_addition(&sm) { '+' } else { '~' },
+                                Style::Addition,
                             );
                         }
                     }
+                    if show_diff {
+                        // Colorize removal with red in diff format.
+                        buffer.set_style_range(
+                            row_num - 2,
+                            (padding as isize + span_start_pos as isize) as usize,
+                            (padding as isize + span_end_pos as isize) as usize,
+                            Style::Removal,
+                            true,
+                        );
+                    }
 
                     // length of the code after substitution
                     let full_sub_len = part
@@ -2129,6 +2207,12 @@ impl<'a> WritableDst<'a> {
     fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> {
         let mut spec = ColorSpec::new();
         match style {
+            Style::Addition => {
+                spec.set_fg(Some(Color::Green)).set_intense(true);
+            }
+            Style::Removal => {
+                spec.set_fg(Some(Color::Red)).set_intense(true);
+            }
             Style::LineAndColumn => {}
             Style::LineNumber => {
                 spec.set_bold(true);
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index fc0924ac5f9..ec29d8016dd 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -160,32 +160,77 @@ pub struct SubstitutionPart {
     pub snippet: String,
 }
 
+/// Used to translate between `Span`s and byte positions within a single output line in highlighted
+/// code of structured suggestions.
+#[derive(Debug, Clone, Copy)]
+pub struct SubstitutionHighlight {
+    start: usize,
+    end: usize,
+}
+
+impl SubstitutionPart {
+    pub fn is_addition(&self, sm: &SourceMap) -> bool {
+        !self.snippet.is_empty()
+            && sm
+                .span_to_snippet(self.span)
+                .map_or(self.span.is_empty(), |snippet| snippet.trim().is_empty())
+    }
+
+    pub fn is_deletion(&self) -> bool {
+        self.snippet.trim().is_empty()
+    }
+
+    pub fn is_replacement(&self, sm: &SourceMap) -> bool {
+        !self.snippet.is_empty()
+            && sm
+                .span_to_snippet(self.span)
+                .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
+    }
+}
+
 impl CodeSuggestion {
     /// Returns the assembled code suggestions, whether they should be shown with an underline
     /// and whether the substitution only differs in capitalization.
-    pub fn splice_lines(&self, sm: &SourceMap) -> Vec<(String, Vec<SubstitutionPart>, bool)> {
+    pub fn splice_lines(
+        &self,
+        sm: &SourceMap,
+    ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
+        // For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
+        // corresponds to the output snippet's lines, while the second level corresponds to the
+        // substrings within that line that should be highlighted.
+
         use rustc_span::{CharPos, Pos};
 
+        /// Append to a buffer the remainder of the line of existing source code, and return the
+        /// count of lines that have been added for accurate highlighting.
         fn push_trailing(
             buf: &mut String,
             line_opt: Option<&Cow<'_, str>>,
             lo: &Loc,
             hi_opt: Option<&Loc>,
-        ) {
+        ) -> usize {
+            let mut line_count = 0;
             let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
             if let Some(line) = line_opt {
                 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
                     let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
                     match hi_opt {
-                        Some(hi) if hi > lo => buf.push_str(&line[lo..hi]),
+                        Some(hi) if hi > lo => {
+                            line_count = line[lo..hi].matches('\n').count();
+                            buf.push_str(&line[lo..hi])
+                        }
                         Some(_) => (),
-                        None => buf.push_str(&line[lo..]),
+                        None => {
+                            line_count = line[lo..].matches('\n').count();
+                            buf.push_str(&line[lo..])
+                        }
                     }
                 }
                 if hi_opt.is_none() {
                     buf.push('\n');
                 }
             }
+            line_count
         }
 
         assert!(!self.substitutions.is_empty());
@@ -220,6 +265,7 @@ impl CodeSuggestion {
                     return None;
                 }
 
+                let mut highlights = vec![];
                 // To build up the result, we do this for each span:
                 // - push the line segment trailing the previous span
                 //   (at the beginning a "phantom" span pointing at the start of the line)
@@ -236,17 +282,29 @@ impl CodeSuggestion {
                     lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
                 let mut buf = String::new();
 
+                let mut line_highlight = vec![];
                 for part in &substitution.parts {
                     let cur_lo = sm.lookup_char_pos(part.span.lo());
                     if prev_hi.line == cur_lo.line {
-                        push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
+                        let mut count =
+                            push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
+                        while count > 0 {
+                            highlights.push(std::mem::take(&mut line_highlight));
+                            count -= 1;
+                        }
                     } else {
-                        push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
+                        highlights.push(std::mem::take(&mut line_highlight));
+                        let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
+                        while count > 0 {
+                            highlights.push(std::mem::take(&mut line_highlight));
+                            count -= 1;
+                        }
                         // push lines between the previous and current span (if any)
                         for idx in prev_hi.line..(cur_lo.line - 1) {
                             if let Some(line) = sf.get_line(idx) {
                                 buf.push_str(line.as_ref());
                                 buf.push('\n');
+                                highlights.push(std::mem::take(&mut line_highlight));
                             }
                         }
                         if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
@@ -257,10 +315,21 @@ impl CodeSuggestion {
                             buf.push_str(&cur_line[..end]);
                         }
                     }
+                    // Add a whole line highlight per line in the snippet.
+                    line_highlight.push(SubstitutionHighlight {
+                        start: cur_lo.col.0,
+                        end: cur_lo.col.0
+                            + part.snippet.split('\n').next().unwrap_or(&part.snippet).len(),
+                    });
+                    for line in part.snippet.split('\n').skip(1) {
+                        highlights.push(std::mem::take(&mut line_highlight));
+                        line_highlight.push(SubstitutionHighlight { start: 0, end: line.len() });
+                    }
                     buf.push_str(&part.snippet);
                     prev_hi = sm.lookup_char_pos(part.span.hi());
                     prev_line = sf.get_line(prev_hi.line - 1);
                 }
+                highlights.push(std::mem::take(&mut line_highlight));
                 let only_capitalization = is_case_difference(sm, &buf, bounding_span);
                 // if the replacement already ends with a newline, don't print the next line
                 if !buf.ends_with('\n') {
@@ -270,7 +339,7 @@ impl CodeSuggestion {
                 while buf.ends_with('\n') {
                     buf.pop();
                 }
-                Some((buf, substitution.parts, only_capitalization))
+                Some((buf, substitution.parts, highlights, only_capitalization))
             })
             .collect()
     }
diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs
index 3fe02bd0cee..64353461e90 100644
--- a/compiler/rustc_errors/src/snippet.rs
+++ b/compiler/rustc_errors/src/snippet.rs
@@ -177,4 +177,6 @@ pub enum Style {
     NoStyle,
     Level(Level),
     Highlight,
+    Addition,
+    Removal,
 }
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 128b51c2061..73b29d65e91 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -281,9 +281,6 @@ declare_features! (
     // feature-group-start: actual feature gates
     // -------------------------------------------------------------------------
 
-    /// Allows using `#[plugin_registrar]` on functions.
-    (active, plugin_registrar, "1.0.0", Some(29597), None),
-
     /// Allows using `#![plugin(myplugin)]`.
     (active, plugin, "1.0.0", Some(29597), None),
 
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 49cca3fbc39..5729384c0da 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -292,18 +292,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // Plugins:
     (
-        sym::plugin_registrar, Normal, template!(Word),
-        Gated(
-            Stability::Deprecated(
-                "https://github.com/rust-lang/rust/pull/64675",
-                Some("may be removed in a future compiler version"),
-            ),
-            sym::plugin_registrar,
-            "compiler plugins are deprecated",
-            cfg_fn!(plugin_registrar)
-        )
-    ),
-    (
         sym::plugin, CrateLevel, template!(List: "name"),
         Gated(
             Stability::Deprecated(
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 46b36f2b704..5cadbd9e5cf 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -136,9 +136,12 @@ declare_features! (
     (removed, main, "1.53.0", Some(29634), None, None),
     (removed, pub_macro_rules, "1.53.0", Some(78855), None,
      Some("removed due to being incomplete, in particular it does not work across crates")),
-     /// Allows the definition of `const` functions with some advanced features.
+    /// Allows the definition of `const` functions with some advanced features.
     (removed, const_fn, "1.54.0", Some(57563), None,
      Some("split into finer-grained feature gates")),
+    /// Allows using `#[plugin_registrar]` on functions.
+    (removed, plugin_registrar, "1.54.0", Some(29597), None,
+     Some("a __rustc_plugin_registrar symbol must now be defined instead")),
 
     /// Allows `#[doc(include = "some-file")]`.
     (removed, external_doc, "1.54.0", Some(44732), None,
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index f0d63f512fc..10217a5f574 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -4,10 +4,12 @@ pub use self::RegionVariableOrigin::*;
 pub use self::SubregionOrigin::*;
 pub use self::ValuePairs::*;
 
+use self::opaque_types::OpaqueTypeMap;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
 
 use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
 
+use hir::def_id::CRATE_DEF_ID;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
@@ -59,6 +61,7 @@ pub mod lattice;
 mod lexical_region_resolve;
 mod lub;
 pub mod nll_relate;
+pub mod opaque_types;
 pub mod outlives;
 pub mod region_constraints;
 pub mod resolve;
@@ -191,6 +194,19 @@ pub struct InferCtxtInner<'tcx> {
     region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
 
     undo_log: InferCtxtUndoLogs<'tcx>,
+
+    // Opaque types found in explicit return types and their
+    // associated fresh inference variable. Writeback resolves these
+    // variables to get the concrete type, which can be used to
+    // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
+    pub opaque_types: OpaqueTypeMap<'tcx>,
+
+    /// A map from inference variables created from opaque
+    /// type instantiations (`ty::Infer`) to the actual opaque
+    /// type (`ty::Opaque`). Used during fallback to map unconstrained
+    /// opaque type inference variables to their corresponding
+    /// opaque type.
+    pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
 }
 
 impl<'tcx> InferCtxtInner<'tcx> {
@@ -204,6 +220,8 @@ impl<'tcx> InferCtxtInner<'tcx> {
             float_unification_storage: ut::UnificationTableStorage::new(),
             region_constraint_storage: Some(RegionConstraintStorage::new()),
             region_obligations: vec![],
+            opaque_types: Default::default(),
+            opaque_types_vars: Default::default(),
         }
     }
 
@@ -273,6 +291,10 @@ impl<'tcx> InferCtxtInner<'tcx> {
 pub struct InferCtxt<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
+    /// The `DefId` of the item in whose context we are performing inference or typeck.
+    /// It is used to check whether an opaque type use is a defining use.
+    pub defining_use_anchor: LocalDefId,
+
     /// During type-checking/inference of a body, `in_progress_typeck_results`
     /// contains a reference to the typeck results being built up, which are
     /// used for reading closure kinds/signatures as they are inferred,
@@ -531,6 +553,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
+    defining_use_anchor: LocalDefId,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -539,15 +562,31 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder { tcx: self, fresh_typeck_results: None }
+        InferCtxtBuilder {
+            tcx: self,
+            defining_use_anchor: CRATE_DEF_ID,
+            fresh_typeck_results: None,
+        }
     }
 }
 
 impl<'tcx> InferCtxtBuilder<'tcx> {
     /// Used only by `rustc_typeck` during body type-checking/inference,
     /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
+    /// Will also change the scope for opaque type defining use checks to the given owner.
     pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
         self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
+        self.with_opaque_type_inference(table_owner)
+    }
+
+    /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
+    /// you need to call this function. Otherwise the opaque type will be treated opaquely.
+    ///
+    /// It is only meant to be called in two places, for typeck
+    /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
+    /// in mir borrowck.
+    pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
+        self.defining_use_anchor = defining_use_anchor;
         self
     }
 
@@ -575,10 +614,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     }
 
     pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder { tcx, ref fresh_typeck_results } = *self;
+        let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
         let in_progress_typeck_results = fresh_typeck_results.as_ref();
         f(InferCtxt {
             tcx,
+            defining_use_anchor,
             in_progress_typeck_results,
             inner: RefCell::new(InferCtxtInner::new()),
             lexical_region_resolutions: RefCell::new(None),
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
new file mode 100644
index 00000000000..d0883f23a4e
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -0,0 +1,47 @@
+use rustc_data_structures::vec_map::VecMap;
+use rustc_hir as hir;
+use rustc_middle::ty::{OpaqueTypeKey, Ty};
+use rustc_span::Span;
+
+pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
+
+/// Information about the opaque types whose values we
+/// are inferring in this function (these are the `impl Trait` that
+/// appear in the return type).
+#[derive(Copy, Clone, Debug)]
+pub struct OpaqueTypeDecl<'tcx> {
+    /// The opaque type (`ty::Opaque`) for this declaration.
+    pub opaque_type: Ty<'tcx>,
+
+    /// The span of this particular definition of the opaque type. So
+    /// for example:
+    ///
+    /// ```ignore (incomplete snippet)
+    /// type Foo = impl Baz;
+    /// fn bar() -> Foo {
+    /// //          ^^^ This is the span we are looking for!
+    /// }
+    /// ```
+    ///
+    /// In cases where the fn returns `(impl Trait, impl Trait)` or
+    /// other such combinations, the result is currently
+    /// over-approximated, but better than nothing.
+    pub definition_span: Span,
+
+    /// The type variable that represents the value of the opaque type
+    /// that we require. In other words, after we compile this function,
+    /// we will be created a constraint like:
+    ///
+    ///     Foo<'a, T> = ?C
+    ///
+    /// where `?C` is the value of this type variable. =) It may
+    /// naturally refer to the type and lifetime parameters in scope
+    /// in this function, though ultimately it should only reference
+    /// those that are arguments to `Foo` in the constraint above. (In
+    /// other words, `?C` should not include `'b`, even though it's a
+    /// lifetime parameter on `foo`.)
+    pub concrete_ty: Ty<'tcx>,
+
+    /// The origin of the opaque type.
+    pub origin: hir::OpaqueTyOrigin,
+}
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 5db027fb5b4..5dc57f6023b 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -741,7 +741,6 @@ pub static DEFAULT_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
     let providers = &mut Providers::default();
     providers.analysis = analysis;
     proc_macro_decls::provide(providers);
-    plugin::build::provide(providers);
     rustc_middle::hir::provide(providers);
     mir::provide(providers);
     mir_build::provide(providers);
@@ -856,8 +855,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
             {
                 entry_point = sess.time("looking_for_entry_point", || tcx.entry_fn(()));
 
-                sess.time("looking_for_plugin_registrar", || tcx.ensure().plugin_registrar_fn(()));
-
                 sess.time("looking_for_derive_registrar", || {
                     tcx.ensure().proc_macro_decls_static(())
                 });
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index 9a96c03cd3c..b970c9e4911 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -60,6 +60,9 @@ pub enum EscapeError {
     /// After a line ending with '\', the next line contains whitespace
     /// characters that are not skipped.
     UnskippedWhitespaceWarning,
+
+    /// After a line ending with '\', multiple lines are skipped.
+    MultipleSkippedLinesWarning,
 }
 
 impl EscapeError {
@@ -67,6 +70,7 @@ impl EscapeError {
     pub fn is_fatal(&self) -> bool {
         match self {
             EscapeError::UnskippedWhitespaceWarning => false,
+            EscapeError::MultipleSkippedLinesWarning => false,
             _ => true,
         }
     }
@@ -315,12 +319,17 @@ where
     where
         F: FnMut(Range<usize>, Result<char, EscapeError>),
     {
-        let str = chars.as_str();
-        let first_non_space = str
+        let tail = chars.as_str();
+        let first_non_space = tail
             .bytes()
             .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
-            .unwrap_or(str.len());
-        let tail = &str[first_non_space..];
+            .unwrap_or(tail.len());
+        if tail[1..first_non_space].contains('\n') {
+            // The +1 accounts for the escaping slash.
+            let end = start + first_non_space + 1;
+            callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
+        }
+        let tail = &tail[first_non_space..];
         if let Some(c) = tail.chars().nth(0) {
             // For error reporting, we would like the span to contain the character that was not
             // skipped.  The +1 is necessary to account for the leading \ that started the escape.
diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs
index 1f4dbb20f4e..fa61554afde 100644
--- a/compiler/rustc_lexer/src/unescape/tests.rs
+++ b/compiler/rustc_lexer/src/unescape/tests.rs
@@ -106,6 +106,10 @@ fn test_unescape_str_warn() {
         assert_eq!(unescaped, expected);
     }
 
+    // Check we can handle escaped newlines at the end of a file.
+    check("\\\n", &[]);
+    check("\\\n ", &[]);
+
     check(
         "\\\n \u{a0} x",
         &[
@@ -115,6 +119,7 @@ fn test_unescape_str_warn() {
             (6..7, Ok('x')),
         ],
     );
+    check("\\\n  \n  x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]);
 }
 
 #[test]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index cf8577a26cf..8d1bf6f55df 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -226,7 +226,7 @@ use rustc_session::config::{self, CrateType};
 use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::CanonicalizedPath;
-use rustc_session::{Session, StableCrateId};
+use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
@@ -787,7 +787,7 @@ pub fn find_plugin_registrar(
     metadata_loader: &dyn MetadataLoader,
     span: Span,
     name: Symbol,
-) -> (PathBuf, StableCrateId) {
+) -> PathBuf {
     match find_plugin_registrar_impl(sess, metadata_loader, name) {
         Ok(res) => res,
         // `core` is always available if we got as far as loading plugins.
@@ -799,7 +799,7 @@ fn find_plugin_registrar_impl<'a>(
     sess: &'a Session,
     metadata_loader: &dyn MetadataLoader,
     name: Symbol,
-) -> Result<(PathBuf, StableCrateId), CrateError> {
+) -> Result<PathBuf, CrateError> {
     info!("find plugin registrar `{}`", name);
     let mut locator = CrateLocator::new(
         sess,
@@ -816,7 +816,7 @@ fn find_plugin_registrar_impl<'a>(
 
     match locator.maybe_load_library_crate()? {
         Some(library) => match library.source.dylib {
-            Some(dylib) => Ok((dylib.0, library.metadata.get_root().stable_crate_id())),
+            Some(dylib) => Ok(dylib.0),
             None => Err(CrateError::NonDylibPlugin(name)),
         },
         None => Err(locator.into_error()),
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 3c16852df05..7c7025ac37a 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1252,9 +1252,6 @@ rustc_queries! {
     query entry_fn(_: ()) -> Option<(DefId, EntryFnType)> {
         desc { "looking up the entry function of a crate" }
     }
-    query plugin_registrar_fn(_: ()) -> Option<LocalDefId> {
-        desc { "looking up the plugin registrar for a crate" }
-    }
     query proc_macro_decls_static(_: ()) -> Option<LocalDefId> {
         desc { "looking up the derive registrar for a crate" }
     }
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 36eb8a4baa8..2bfa51f27bb 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -105,7 +105,7 @@ fn mir_borrowck<'tcx>(
     let (input_body, promoted) = tcx.mir_promoted(def);
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
 
-    let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
+    let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
         do_mir_borrowck(&infcx, input_body, promoted)
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index 3fb06cd2f5f..f69d08a6d59 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -179,54 +179,55 @@ pub(crate) fn type_check<'mir, 'tcx>(
             liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
 
             translate_outlives_facts(&mut cx);
-            let mut opaque_type_values = cx.opaque_type_values;
-
-            for (_, revealed_ty) in &mut opaque_type_values {
-                *revealed_ty = infcx.resolve_vars_if_possible(*revealed_ty);
-                if revealed_ty.has_infer_types_or_consts() {
-                    infcx.tcx.sess.delay_span_bug(
-                        body.span,
-                        &format!("could not resolve {:#?}", revealed_ty.kind()),
-                    );
-                    *revealed_ty = infcx.tcx.ty_error();
-                }
-            }
-
-            opaque_type_values.retain(|(opaque_type_key, resolved_ty)| {
-                let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
-                    *def_id == opaque_type_key.def_id
-                } else {
-                    false
-                };
+            let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
 
-                if concrete_is_opaque {
-                    // We're using an opaque `impl Trait` type without
-                    // 'revealing' it. For example, code like this:
-                    //
-                    // type Foo = impl Debug;
-                    // fn foo1() -> Foo { ... }
-                    // fn foo2() -> Foo { foo1() }
-                    //
-                    // In `foo2`, we're not revealing the type of `Foo` - we're
-                    // just treating it as the opaque type.
-                    //
-                    // When this occurs, we do *not* want to try to equate
-                    // the concrete type with the underlying defining type
-                    // of the opaque type - this will always fail, since
-                    // the defining type of an opaque type is always
-                    // some other type (e.g. not itself)
-                    // Essentially, none of the normal obligations apply here -
-                    // we're just passing around some unknown opaque type,
-                    // without actually looking at the underlying type it
-                    // gets 'revealed' into
-                    debug!(
-                        "eq_opaque_type_and_type: non-defining use of {:?}",
-                        opaque_type_key.def_id,
-                    );
-                }
-                !concrete_is_opaque
-            });
             opaque_type_values
+                .into_iter()
+                .filter_map(|(opaque_type_key, decl)| {
+                    let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
+                    if revealed_ty.has_infer_types_or_consts() {
+                        infcx.tcx.sess.delay_span_bug(
+                            body.span,
+                            &format!("could not resolve {:#?}", revealed_ty.kind()),
+                        );
+                        revealed_ty = infcx.tcx.ty_error();
+                    }
+                    let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() {
+                        *def_id == opaque_type_key.def_id
+                    } else {
+                        false
+                    };
+
+                    if concrete_is_opaque {
+                        // We're using an opaque `impl Trait` type without
+                        // 'revealing' it. For example, code like this:
+                        //
+                        // type Foo = impl Debug;
+                        // fn foo1() -> Foo { ... }
+                        // fn foo2() -> Foo { foo1() }
+                        //
+                        // In `foo2`, we're not revealing the type of `Foo` - we're
+                        // just treating it as the opaque type.
+                        //
+                        // When this occurs, we do *not* want to try to equate
+                        // the concrete type with the underlying defining type
+                        // of the opaque type - this will always fail, since
+                        // the defining type of an opaque type is always
+                        // some other type (e.g. not itself)
+                        // Essentially, none of the normal obligations apply here -
+                        // we're just passing around some unknown opaque type,
+                        // without actually looking at the underlying type it
+                        // gets 'revealed' into
+                        debug!(
+                            "eq_opaque_type_and_type: non-defining use of {:?}",
+                            opaque_type_key.def_id,
+                        );
+                        None
+                    } else {
+                        Some((opaque_type_key, revealed_ty))
+                    }
+                })
+                .collect()
         },
     );
 
@@ -865,7 +866,6 @@ struct TypeChecker<'a, 'tcx> {
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
     universal_region_relations: &'a UniversalRegionRelations<'tcx>,
-    opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
 }
 
 struct BorrowCheckContext<'a, 'tcx> {
@@ -1025,7 +1025,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             borrowck_context,
             reported_errors: Default::default(),
             universal_region_relations,
-            opaque_type_values: VecMap::default(),
         };
         checker.check_user_type_annotations();
         checker
@@ -1289,10 +1288,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let body = self.body;
         let mir_def_id = body.source.def_id().expect_local();
 
-        let mut opaque_type_values = VecMap::new();
-
         debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id);
-        let opaque_type_map = self.fully_perform_op(
+        self.fully_perform_op(
             locations,
             category,
             CustomTypeOp::new(
@@ -1307,20 +1304,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     // to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
                     // (Note that the key of the map is both the def-id of `Foo` along with
                     // any generic parameters.)
-                    let (output_ty, opaque_type_map) =
-                        obligations.add(infcx.instantiate_opaque_types(
-                            mir_def_id,
-                            dummy_body_id,
-                            param_env,
-                            anon_ty,
-                            locations.span(body),
-                        ));
+                    let output_ty = obligations.add(infcx.instantiate_opaque_types(
+                        dummy_body_id,
+                        param_env,
+                        anon_ty,
+                        locations.span(body),
+                    ));
                     debug!(
                         "eq_opaque_type_and_type: \
                          instantiated output_ty={:?} \
-                         opaque_type_map={:#?} \
                          revealed_ty={:?}",
-                        output_ty, opaque_type_map, revealed_ty
+                        output_ty, revealed_ty
                     );
 
                     // Make sure that the inferred types are well-formed. I'm
@@ -1338,48 +1332,38 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             .eq(output_ty, revealed_ty)?,
                     );
 
-                    for &(opaque_type_key, opaque_decl) in &opaque_type_map {
-                        opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty);
-                    }
-
                     debug!("eq_opaque_type_and_type: equated");
 
-                    Ok(InferOk {
-                        value: Some(opaque_type_map),
-                        obligations: obligations.into_vec(),
-                    })
+                    Ok(InferOk { value: (), obligations: obligations.into_vec() })
                 },
                 || "input_output".to_string(),
             ),
         )?;
 
-        self.opaque_type_values.extend(opaque_type_values);
-
         let universal_region_relations = self.universal_region_relations;
 
         // Finally, if we instantiated the anon types successfully, we
         // have to solve any bounds (e.g., `-> impl Iterator` needs to
         // prove that `T: Iterator` where `T` is the type we
         // instantiated it with).
-        if let Some(opaque_type_map) = opaque_type_map {
-            for (opaque_type_key, opaque_decl) in opaque_type_map {
-                self.fully_perform_op(
-                    locations,
-                    ConstraintCategory::OpaqueType,
-                    CustomTypeOp::new(
-                        |infcx| {
-                            infcx.constrain_opaque_type(
-                                opaque_type_key,
-                                &opaque_decl,
-                                GenerateMemberConstraints::IfNoStaticBound,
-                                universal_region_relations,
-                            );
-                            Ok(InferOk { value: (), obligations: vec![] })
-                        },
-                        || "opaque_type_map".to_string(),
-                    ),
-                )?;
-            }
+        let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
+        for (opaque_type_key, opaque_decl) in opaque_type_map {
+            self.fully_perform_op(
+                locations,
+                ConstraintCategory::OpaqueType,
+                CustomTypeOp::new(
+                    |infcx| {
+                        infcx.constrain_opaque_type(
+                            opaque_type_key,
+                            &opaque_decl,
+                            GenerateMemberConstraints::IfNoStaticBound,
+                            universal_region_relations,
+                        );
+                        Ok(InferOk { value: (), obligations: vec![] })
+                    },
+                    || "opaque_type_map".to_string(),
+                ),
+            )?;
         }
         Ok(())
     }
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 4e95cdc0efa..aa6b424ce2b 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -280,6 +280,11 @@ pub(crate) fn emit_unescape_error(
                 format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
             handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
         }
+        EscapeError::MultipleSkippedLinesWarning => {
+            let msg = "multiple lines skipped by escaped newline";
+            let bottom_msg = "skipping everything up to and including this point";
+            handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
+        }
     }
 }
 
diff --git a/compiler/rustc_plugin_impl/src/build.rs b/compiler/rustc_plugin_impl/src/build.rs
deleted file mode 100644
index b95c4a72019..00000000000
--- a/compiler/rustc_plugin_impl/src/build.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-//! Used by `rustc` when compiling a plugin crate.
-
-use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
-
-struct RegistrarFinder<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    registrars: Vec<(LocalDefId, Span)>,
-}
-
-impl<'v, 'tcx> ItemLikeVisitor<'v> for RegistrarFinder<'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        if let hir::ItemKind::Fn(..) = item.kind {
-            let attrs = self.tcx.hir().attrs(item.hir_id());
-            if self.tcx.sess.contains_name(attrs, sym::plugin_registrar) {
-                self.registrars.push((item.def_id, item.span));
-            }
-        }
-    }
-
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-
-    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-
-    fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
-}
-
-/// Finds the function marked with `#[plugin_registrar]`, if any.
-fn plugin_registrar_fn(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
-    let mut finder = RegistrarFinder { tcx, registrars: Vec::new() };
-    tcx.hir().krate().visit_all_item_likes(&mut finder);
-
-    let (def_id, span) = finder.registrars.pop()?;
-
-    if !finder.registrars.is_empty() {
-        let diagnostic = tcx.sess.diagnostic();
-        let mut e = diagnostic.struct_err("multiple plugin registration functions found");
-        e.span_note(span, "one is here");
-        for &(_, span) in &finder.registrars {
-            e.span_note(span, "one is here");
-        }
-        e.emit();
-        diagnostic.abort_if_errors();
-        unreachable!();
-    }
-
-    Some(def_id)
-}
-
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers { plugin_registrar_fn, ..*providers };
-}
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index 5bf4d300e9e..a1e13a1abb6 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -12,7 +12,6 @@
 
 use rustc_lint::LintStore;
 
-pub mod build;
 pub mod load;
 
 /// Structure used to register plugins.
diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs
index 687f7db221f..5da02e3a489 100644
--- a/compiler/rustc_plugin_impl/src/load.rs
+++ b/compiler/rustc_plugin_impl/src/load.rs
@@ -55,20 +55,13 @@ fn load_plugin(
     metadata_loader: &dyn MetadataLoader,
     ident: Ident,
 ) {
-    let (lib, disambiguator) =
-        locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
-    let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
-    let fun = dylink_registrar(sess, ident.span, lib, symbol);
+    let lib = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
+    let fun = dylink_registrar(sess, ident.span, lib);
     plugins.push(fun);
 }
 
 // Dynamically link a registrar function into the compiler process.
-fn dylink_registrar(
-    sess: &Session,
-    span: Span,
-    path: PathBuf,
-    symbol: String,
-) -> PluginRegistrarFn {
+fn dylink_registrar(sess: &Session, span: Span, path: PathBuf) -> PluginRegistrarFn {
     use rustc_metadata::dynamic_lib::DynamicLibrary;
 
     // Make sure the path contains a / or the linker will search for it.
@@ -83,7 +76,7 @@ fn dylink_registrar(
     };
 
     unsafe {
-        let registrar = match lib.symbol(&symbol) {
+        let registrar = match lib.symbol("__rustc_plugin_registrar") {
             Ok(registrar) => mem::transmute::<*mut u8, PluginRegistrarFn>(registrar),
             // again fatal if we can't register macros
             Err(err) => sess.span_fatal(span, &err),
@@ -91,7 +84,7 @@ fn dylink_registrar(
 
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long
-        // (e.g., an @-box cycle or a thread).
+        // (e.g., an Rc cycle or a thread).
         mem::forget(lib);
 
         registrar
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index d5c759623e3..0b1a99922d6 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -792,12 +792,6 @@ impl Session {
             )
     }
 
-    /// Returns the symbol name for the registrar function,
-    /// given the crate `Svh` and the function `DefIndex`.
-    pub fn generate_plugin_registrar_symbol(&self, stable_crate_id: StableCrateId) -> String {
-        format!("__rustc_plugin_registrar_{:08x}__", stable_crate_id.to_u64())
-    }
-
     pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
         format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64())
     }
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 0c64fe6ea60..1b4e6b4e381 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -55,7 +55,8 @@ pub(super) fn mangle(
 
     let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
 
-    let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false }
+    let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false };
+    printer
         .print_def_path(
             def_id,
             if let ty::InstanceDef::DropGlue(_, _) = instance.def {
@@ -198,7 +199,7 @@ struct SymbolPrinter<'tcx> {
 // `PrettyPrinter` aka pretty printing of e.g. types in paths,
 // symbol names should have their own printing machinery.
 
-impl Printer<'tcx> for SymbolPrinter<'tcx> {
+impl Printer<'tcx> for &mut SymbolPrinter<'tcx> {
     type Error = fmt::Error;
 
     type Path = Self;
@@ -242,7 +243,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> {
         Ok(self)
     }
 
-    fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+    fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         // only print integers
         if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val {
             if ct.ty.is_integral() {
@@ -253,7 +254,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> {
         Ok(self)
     }
 
-    fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+    fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
         self.write_str(&self.tcx.crate_name(cnum).as_str())?;
         Ok(self)
     }
@@ -344,7 +345,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> {
     }
 }
 
-impl PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
+impl PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> {
     fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
         false
     }
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index ba59ff96f65..850d44eb339 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -164,10 +164,6 @@ fn compute_symbol_name(
 
     // FIXME(eddyb) Precompute a custom symbol name based on attributes.
     let is_foreign = if let Some(def_id) = def_id.as_local() {
-        if tcx.plugin_registrar_fn(()) == Some(def_id) {
-            let stable_crate_id = tcx.sess.local_stable_crate_id();
-            return tcx.sess.generate_plugin_registrar_symbol(stable_crate_id);
-        }
         if tcx.proc_macro_decls_static(()) == Some(def_id) {
             let stable_crate_id = tcx.sess.local_stable_crate_id();
             return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 95c81c5c729..1a195ce18ec 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -2,11 +2,11 @@ use crate::infer::InferCtxtExt as _;
 use crate::traits::{self, ObligationCause, PredicateObligation};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
 use rustc_infer::infer::free_regions::FreeRegionRelations;
+use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{self, InferCtxt, InferOk};
 use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
@@ -16,72 +16,6 @@ use rustc_span::Span;
 
 use std::ops::ControlFlow;
 
-pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
-
-/// Information about the opaque types whose values we
-/// are inferring in this function (these are the `impl Trait` that
-/// appear in the return type).
-#[derive(Copy, Clone, Debug)]
-pub struct OpaqueTypeDecl<'tcx> {
-    /// The opaque type (`ty::Opaque`) for this declaration.
-    pub opaque_type: Ty<'tcx>,
-
-    /// The span of this particular definition of the opaque type. So
-    /// for example:
-    ///
-    /// ```ignore (incomplete snippet)
-    /// type Foo = impl Baz;
-    /// fn bar() -> Foo {
-    /// //          ^^^ This is the span we are looking for!
-    /// }
-    /// ```
-    ///
-    /// In cases where the fn returns `(impl Trait, impl Trait)` or
-    /// other such combinations, the result is currently
-    /// over-approximated, but better than nothing.
-    pub definition_span: Span,
-
-    /// The type variable that represents the value of the opaque type
-    /// that we require. In other words, after we compile this function,
-    /// we will be created a constraint like:
-    ///
-    ///     Foo<'a, T> = ?C
-    ///
-    /// where `?C` is the value of this type variable. =) It may
-    /// naturally refer to the type and lifetime parameters in scope
-    /// in this function, though ultimately it should only reference
-    /// those that are arguments to `Foo` in the constraint above. (In
-    /// other words, `?C` should not include `'b`, even though it's a
-    /// lifetime parameter on `foo`.)
-    pub concrete_ty: Ty<'tcx>,
-
-    /// Returns `true` if the `impl Trait` bounds include region bounds.
-    /// For example, this would be true for:
-    ///
-    ///     fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
-    ///
-    /// but false for:
-    ///
-    ///     fn foo<'c>() -> impl Trait<'c>
-    ///
-    /// unless `Trait` was declared like:
-    ///
-    ///     trait Trait<'c>: 'c
-    ///
-    /// in which case it would be true.
-    ///
-    /// This is used during regionck to decide whether we need to
-    /// impose any additional constraints to ensure that region
-    /// variables in `concrete_ty` wind up being constrained to
-    /// something from `substs` (or, at minimum, things that outlive
-    /// the fn body). (Ultimately, writeback is responsible for this
-    /// check.)
-    pub has_required_region_bounds: bool,
-
-    /// The origin of the opaque type.
-    pub origin: hir::OpaqueTyOrigin,
-}
-
 /// Whether member constraints should be generated for all opaque types
 #[derive(Debug)]
 pub enum GenerateMemberConstraints {
@@ -98,18 +32,13 @@ pub enum GenerateMemberConstraints {
 pub trait InferCtxtExt<'tcx> {
     fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
         &self,
-        parent_def_id: LocalDefId,
         body_id: hir::HirId,
         param_env: ty::ParamEnv<'tcx>,
         value: T,
         value_span: Span,
-    ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>;
+    ) -> InferOk<'tcx, T>;
 
-    fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
-        &self,
-        opaque_types: &OpaqueTypeMap<'tcx>,
-        free_region_relations: &FRR,
-    );
+    fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR);
 
     fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
         &self,
@@ -164,28 +93,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     /// - `value_span` -- the span where the value came from, used in error reporting
     fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
         &self,
-        parent_def_id: LocalDefId,
         body_id: hir::HirId,
         param_env: ty::ParamEnv<'tcx>,
         value: T,
         value_span: Span,
-    ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
+    ) -> InferOk<'tcx, T> {
         debug!(
-            "instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \
+            "instantiate_opaque_types(value={:?}, body_id={:?}, \
              param_env={:?}, value_span={:?})",
-            value, parent_def_id, body_id, param_env, value_span,
+            value, body_id, param_env, value_span,
         );
-        let mut instantiator = Instantiator {
-            infcx: self,
-            parent_def_id,
-            body_id,
-            param_env,
-            value_span,
-            opaque_types: Default::default(),
-            obligations: vec![],
-        };
+        let mut instantiator =
+            Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
         let value = instantiator.instantiate_opaque_types_in_map(value);
-        InferOk { value: (value, instantiator.opaque_types), obligations: instantiator.obligations }
+        InferOk { value, obligations: instantiator.obligations }
     }
 
     /// Given the map `opaque_types` containing the opaque
@@ -350,12 +271,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
     /// - `free_region_relations` -- something that can be used to relate
     ///   the free regions (`'a`) that appear in the impl trait.
-    fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
-        &self,
-        opaque_types: &OpaqueTypeMap<'tcx>,
-        free_region_relations: &FRR,
-    ) {
-        for &(opaque_type_key, opaque_defn) in opaque_types {
+    fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR) {
+        let opaque_types = self.inner.borrow().opaque_types.clone();
+        for (opaque_type_key, opaque_defn) in opaque_types {
             self.constrain_opaque_type(
                 opaque_type_key,
                 &opaque_defn,
@@ -403,19 +321,35 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
         let span = tcx.def_span(def_id);
 
-        // If there are required region bounds, we can use them.
-        if opaque_defn.has_required_region_bounds {
-            let bounds = tcx.explicit_item_bounds(def_id);
-            debug!("{:#?}", bounds);
-            let bounds: Vec<_> =
-                bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect();
-            debug!("{:#?}", bounds);
-            let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
-
-            let required_region_bounds =
-                required_region_bounds(tcx, opaque_type, bounds.into_iter());
-            debug_assert!(!required_region_bounds.is_empty());
-
+        // Check if the `impl Trait` bounds include region bounds.
+        // For example, this would be true for:
+        //
+        //     fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
+        //
+        // but false for:
+        //
+        //     fn foo<'c>() -> impl Trait<'c>
+        //
+        // unless `Trait` was declared like:
+        //
+        //     trait Trait<'c>: 'c
+        //
+        // in which case it would be true.
+        //
+        // This is used during regionck to decide whether we need to
+        // impose any additional constraints to ensure that region
+        // variables in `concrete_ty` wind up being constrained to
+        // something from `substs` (or, at minimum, things that outlive
+        // the fn body). (Ultimately, writeback is responsible for this
+        // check.)
+        let bounds = tcx.explicit_item_bounds(def_id);
+        debug!("{:#?}", bounds);
+        let bounds = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs));
+        debug!("{:#?}", bounds);
+        let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
+
+        let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds);
+        if !required_region_bounds.is_empty() {
             for required_region in required_region_bounds {
                 concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
                     op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
@@ -914,11 +848,9 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
 
 struct Instantiator<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
-    parent_def_id: LocalDefId,
     body_id: hir::HirId,
     param_env: ty::ParamEnv<'tcx>,
     value_span: Span,
-    opaque_types: OpaqueTypeMap<'tcx>,
     obligations: Vec<PredicateObligation<'tcx>>,
 }
 
@@ -968,7 +900,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
                     // ```
                     if let Some(def_id) = def_id.as_local() {
                         let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                        let parent_def_id = self.parent_def_id;
+                        let parent_def_id = self.infcx.defining_use_anchor;
                         let def_scope_default = || {
                             let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
                             parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
@@ -980,14 +912,14 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
                                     impl_trait_fn: Some(parent),
                                     origin,
                                     ..
-                                }) => (parent == self.parent_def_id.to_def_id(), origin),
+                                }) => (parent == parent_def_id.to_def_id(), origin),
                                 // Named `type Foo = impl Bar;`
                                 hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                                     impl_trait_fn: None,
                                     origin,
                                     ..
                                 }) => (
-                                    may_define_opaque_type(tcx, self.parent_def_id, opaque_hir_id),
+                                    may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
                                     origin,
                                 ),
                                 _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
@@ -1028,32 +960,14 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
 
         // Use the same type variable if the exact same opaque type appears more
         // than once in the return type (e.g., if it's passed to a type alias).
-        if let Some(opaque_defn) = self.opaque_types.get(&opaque_type_key) {
+        if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
             debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
             return opaque_defn.concrete_ty;
         }
-        let span = tcx.def_span(def_id);
-        debug!("fold_opaque_ty {:?} {:?}", self.value_span, span);
-        let ty_var = infcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
-
-        let item_bounds = tcx.explicit_item_bounds(def_id);
-        debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
-        let bounds: Vec<_> =
-            item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
-
-        let param_env = tcx.param_env(def_id);
-        let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in(
-            ObligationCause::misc(span, self.body_id),
-            param_env,
-            bounds,
-        );
-        self.obligations.extend(obligations);
-
-        debug!("instantiate_opaque_types: bounds={:?}", bounds);
-
-        let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied());
-        debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
+        let ty_var = infcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::TypeInference,
+            span: self.value_span,
+        });
 
         // Make sure that we are in fact defining the *entire* type
         // (e.g., `type Foo<T: Bound> = impl Bar;` needs to be
@@ -1068,23 +982,46 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
         // Foo, impl Bar)`.
         let definition_span = self.value_span;
 
-        self.opaque_types.insert(
-            OpaqueTypeKey { def_id, substs },
-            OpaqueTypeDecl {
-                opaque_type: ty,
-                definition_span,
-                concrete_ty: ty_var,
-                has_required_region_bounds: !required_region_bounds.is_empty(),
-                origin,
-            },
-        );
+        {
+            let mut infcx = self.infcx.inner.borrow_mut();
+            infcx.opaque_types.insert(
+                OpaqueTypeKey { def_id, substs },
+                OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
+            );
+            infcx.opaque_types_vars.insert(ty_var, ty);
+        }
+
         debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
+        self.compute_opaque_type_obligations(opaque_type_key);
+
+        ty_var
+    }
+
+    fn compute_opaque_type_obligations(&mut self, opaque_type_key: OpaqueTypeKey<'tcx>) {
+        let infcx = self.infcx;
+        let tcx = infcx.tcx;
+        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+        let item_bounds = tcx.explicit_item_bounds(def_id);
+        debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
+        let bounds: Vec<_> =
+            item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
+
+        let param_env = tcx.param_env(def_id);
+        let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in(
+            ObligationCause::misc(self.value_span, self.body_id),
+            param_env,
+            bounds,
+        );
+        self.obligations.extend(obligations);
+
+        debug!("instantiate_opaque_types: bounds={:?}", bounds);
 
         for predicate in &bounds {
             if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
                 if projection.ty.references_error() {
                     // No point on adding these obligations since there's a type error involved.
-                    return ty_var;
+                    return;
                 }
             }
         }
@@ -1096,14 +1033,13 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
             // This also instantiates nested instances of `impl Trait`.
             let predicate = self.instantiate_opaque_types_in_map(predicate);
 
-            let cause = traits::ObligationCause::new(span, self.body_id, traits::OpaqueType);
+            let cause =
+                traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
 
             // Require that the predicate holds for the concrete type.
             debug!("instantiate_opaque_types: predicate={:?}", predicate);
             self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
         }
-
-        ty_var
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 3f713ce3c39..ac07cc1f034 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -245,9 +245,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
                     root_obligation.cause.code.peel_derives()
                 {
-                    if let Some(cause) =
-                        self.tcx.diagnostic_hir_wf_check((obligation.predicate, wf_loc.clone()))
-                    {
+                    if let Some(cause) = self.tcx.diagnostic_hir_wf_check((
+                        tcx.erase_regions(obligation.predicate),
+                        wf_loc.clone(),
+                    )) {
                         obligation.cause = cause;
                         span = obligation.cause.span;
                     }
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index dee81510b79..10c3a97e73a 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -593,13 +593,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         orig_expected: Expectation<'tcx>,
     ) -> Option<Span> {
         match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
-            (Expectation::ExpectHasType(expected), Some((id, ty)))
+            (Expectation::ExpectHasType(expected), Some((_id, ty)))
                 if self.in_tail_expr && self.can_coerce(outer_ty, expected) =>
             {
                 let impl_trait_ret_ty =
-                    self.infcx.instantiate_opaque_types(id, self.body_id, self.param_env, ty, span);
-                let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
-                for o in impl_trait_ret_ty.obligations {
+                    self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span);
+                assert!(
+                    impl_trait_ret_ty.obligations.is_empty(),
+                    "we should never get new obligations here"
+                );
+                let obligations = self.fulfillment_cx.borrow().pending_obligations();
+                let mut suggest_box = !obligations.is_empty();
+                for o in obligations {
                     match o.predicate.kind().skip_binder() {
                         ty::PredicateKind::Trait(t, constness) => {
                             let pred = ty::PredicateKind::Trait(
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index ba99e0c03d8..8b5b7e3e52c 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -94,69 +94,8 @@ pub(super) fn check_fn<'a, 'tcx>(
 
     let declared_ret_ty = fn_sig.output();
 
-    let feature = match tcx.hir().get(fn_id) {
-        // TAIT usage in function return position.
-        // Example:
-        //
-        // ```rust
-        // type Foo = impl Debug;
-        // fn bar() -> Foo { 42 }
-        // ```
-        Node::Item(hir::Item { kind: ItemKind::Fn(..), .. }) |
-        // TAIT usage in associated function return position.
-        //
-        // Example with a free type alias:
-        //
-        // ```rust
-        // type Foo = impl Debug;
-        // impl SomeTrait for SomeType {
-        //     fn bar() -> Foo { 42 }
-        // }
-        // ```
-        //
-        // Example with an associated TAIT:
-        //
-        // ```rust
-        // impl SomeTrait for SomeType {
-        //     type Foo = impl Debug;
-        //     fn bar() -> Self::Foo { 42 }
-        // }
-        // ```
-        Node::ImplItem(hir::ImplItem {
-            kind: hir::ImplItemKind::Fn(..), ..
-        }) => None,
-        // Forbid TAIT in trait declarations for now.
-        // Examples:
-        //
-        // ```rust
-        // type Foo = impl Debug;
-        // trait Bar {
-        //     fn bar() -> Foo;
-        // }
-        // trait Bop {
-        //     type Bop: PartialEq<Foo>;
-        // }
-        // ```
-        Node::TraitItem(hir::TraitItem {
-            kind: hir::TraitItemKind::Fn(..),
-            ..
-        }) |
-        // Forbid TAIT in closure return position for now.
-        // Example:
-        //
-        // ```rust
-        // type Foo = impl Debug;
-        // let x = |y| -> Foo { 42 + y };
-        // ```
-        Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => Some(sym::type_alias_impl_trait),
-        node => bug!("Item being checked wasn't a function/closure: {:?}", node),
-    };
-    let revealed_ret_ty = fcx.instantiate_opaque_types_from_value(
-        fn_id,
-        declared_ret_ty,
-        decl.output.span(),
-        feature,
-    );
+    let revealed_ret_ty =
+        fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span());
     debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
     fcx.ret_type_span = Some(decl.output.span());
@@ -711,10 +650,11 @@ fn check_opaque_meets_bounds<'tcx>(
 
         let misc_cause = traits::ObligationCause::misc(span, hir_id);
 
-        let (_, opaque_type_map) = inh.register_infer_ok_obligations(
-            infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span),
+        let _ = inh.register_infer_ok_obligations(
+            infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
         );
 
+        let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
         for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
             match infcx
                 .at(&misc_cause, param_env)
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 831b573e156..a5362856511 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1313,15 +1313,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .emit();
             }
         } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
-            let no_accessible_remaining_fields = remaining_fields
-                .iter()
-                .find(|(_, (_, field))| {
-                    field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
-                })
-                .is_none();
+            let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
+                !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
+            });
 
-            if no_accessible_remaining_fields {
-                self.report_no_accessible_fields(adt_ty, span);
+            if inaccessible_remaining_fields {
+                self.report_inaccessible_fields(adt_ty, span);
             } else {
                 self.report_missing_fields(adt_ty, span, remaining_fields);
             }
@@ -1398,7 +1395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         .emit();
     }
 
-    /// Report an error for a struct field expression when there are no visible fields.
+    /// Report an error for a struct field expression when there are invisible fields.
     ///
     /// ```text
     /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
@@ -1409,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// error: aborting due to previous error
     /// ```
-    fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
+    fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
         self.tcx.sess.span_err(
             span,
             &format!(
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index f5776ae7cf6..b84a79b768c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -29,12 +29,11 @@ use rustc_middle::ty::{
 };
 use rustc_session::lint;
 use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_session::parse::feature_err;
 use rustc_span::edition::Edition;
+use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{original_sp, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{self, BytePos, MultiSpan, Span};
-use rustc_span::{hygiene::DesugaringKind, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
@@ -363,50 +362,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Replaces the opaque types from the given value with type variables,
     /// and records the `OpaqueTypeMap` for later use during writeback. See
     /// `InferCtxt::instantiate_opaque_types` for more details.
+    #[instrument(skip(self, value_span), level = "debug")]
     pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
         &self,
-        parent_id: hir::HirId,
         value: T,
         value_span: Span,
-        feature: Option<Symbol>,
     ) -> T {
-        let parent_def_id = self.tcx.hir().local_def_id(parent_id);
-        debug!(
-            "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
-            parent_def_id, value
-        );
-
-        let (value, opaque_type_map) =
-            self.register_infer_ok_obligations(self.instantiate_opaque_types(
-                parent_def_id,
-                self.body_id,
-                self.param_env,
-                value,
-                value_span,
-            ));
-
-        let mut opaque_types = self.opaque_types.borrow_mut();
-        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
-
-        for (ty, decl) in opaque_type_map {
-            if let Some(feature) = feature {
-                if let hir::OpaqueTyOrigin::TyAlias = decl.origin {
-                    if !self.tcx.features().enabled(feature) {
-                        feature_err(
-                            &self.tcx.sess.parse_sess,
-                            feature,
-                            value_span,
-                            "type alias impl trait is not permitted here",
-                        )
-                        .emit();
-                    }
-                }
-            }
-            let _ = opaque_types.insert(ty, decl);
-            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
-        }
-
-        value
+        self.register_infer_ok_obligations(self.instantiate_opaque_types(
+            self.body_id,
+            self.param_env,
+            value,
+            value_span,
+        ))
     }
 
     /// Convenience method which tracks extra diagnostic information for normalization
@@ -726,7 +693,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // We treat this as a non-defining use by making the inference
                 // variable fall back to the opaque type itself.
                 if let FallbackMode::All = mode {
-                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
+                    if let Some(opaque_ty) = self.infcx.inner.borrow().opaque_types_vars.get(ty) {
                         debug!(
                             "fallback_if_possible: falling back opaque type var {:?} to {:?}",
                             ty, opaque_ty
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index 7e43e36fe55..fb7beae70ba 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -1,18 +1,15 @@
 use super::callee::DeferredCallResolution;
 use super::MaybeInProgressTables;
 
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::HirIdMap;
 use rustc_infer::infer;
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{self, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::OpaqueTypeDecl;
 use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
 
 use std::cell::RefCell;
@@ -55,19 +52,6 @@ pub struct Inherited<'a, 'tcx> {
     pub(super) deferred_generator_interiors:
         RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
 
-    // Opaque types found in explicit return types and their
-    // associated fresh inference variable. Writeback resolves these
-    // variables to get the concrete type, which can be used to
-    // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
-    pub(super) opaque_types: RefCell<VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>>,
-
-    /// A map from inference variables created from opaque
-    /// type instantiations (`ty::Infer`) to the actual opaque
-    /// type (`ty::Opaque`). Used during fallback to map unconstrained
-    /// opaque type inference variables to their corresponding
-    /// opaque type.
-    pub(super) opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
-
     pub(super) body_id: Option<hir::BodyId>,
 }
 
@@ -124,8 +108,6 @@ impl Inherited<'a, 'tcx> {
             deferred_call_resolutions: RefCell::new(Default::default()),
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_generator_interiors: RefCell::new(Vec::new()),
-            opaque_types: RefCell::new(Default::default()),
-            opaque_types_vars: RefCell::new(Default::default()),
             body_id,
         }
     }
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 77586ce4852..c7a7462668a 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1695,8 +1695,8 @@ fn print_disambiguation_help(
     source_map: &source_map::SourceMap,
 ) {
     let mut applicability = Applicability::MachineApplicable;
-    let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
-        format!(
+    let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
+        let args = format!(
             "({}{})",
             if rcvr_ty.is_region_ptr() {
                 if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
@@ -1710,12 +1710,12 @@ fn print_disambiguation_help(
                 }))
                 .collect::<Vec<_>>()
                 .join(", "),
-        )
+        );
+        (span, format!("{}::{}{}", trait_name, item_name, args))
     } else {
-        String::new()
+        (span.with_hi(item_name.span.lo()), format!("{}::", trait_name))
     };
-    let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
-    err.span_suggestion(
+    err.span_suggestion_verbose(
         span,
         &format!(
             "disambiguate the {} for {}",
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index db77d155a2b..dae574bb7bf 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1250,15 +1250,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
             }
         } else if !etc && !unmentioned_fields.is_empty() {
-            let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| {
-                field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
-            });
+            let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
+                .iter()
+                .copied()
+                .filter(|(field, _)| {
+                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+                })
+                .collect();
 
-            if no_accessible_unmentioned_fields {
+            if accessible_unmentioned_fields.is_empty() {
                 unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
             } else {
-                unmentioned_err =
-                    Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields));
+                unmentioned_err = Some(self.error_unmentioned_fields(
+                    pat,
+                    &accessible_unmentioned_fields,
+                    accessible_unmentioned_fields.len() != unmentioned_fields.len(),
+                    &fields,
+                ));
             }
         }
         match (inexistent_fields_err, unmentioned_err) {
@@ -1583,17 +1591,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         pat: &Pat<'_>,
         unmentioned_fields: &[(&ty::FieldDef, Ident)],
+        have_inaccessible_fields: bool,
         fields: &'tcx [hir::PatField<'tcx>],
     ) -> DiagnosticBuilder<'tcx> {
+        let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
         let field_names = if unmentioned_fields.len() == 1 {
-            format!("field `{}`", unmentioned_fields[0].1)
+            format!("field `{}`{}", unmentioned_fields[0].1, inaccessible)
         } else {
             let fields = unmentioned_fields
                 .iter()
                 .map(|(_, name)| format!("`{}`", name))
                 .collect::<Vec<String>>()
                 .join(", ");
-            format!("fields {}", fields)
+            format!("fields {}{}", fields, inaccessible)
         };
         let mut err = struct_span_err!(
             self.tcx.sess,
@@ -1624,17 +1634,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.span_suggestion(
             sp,
             &format!(
-                "include the missing field{} in the pattern",
+                "include the missing field{} in the pattern{}",
                 if len == 1 { "" } else { "s" },
+                if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
             ),
             format!(
-                "{}{}{}",
+                "{}{}{}{}",
                 prefix,
                 unmentioned_fields
                     .iter()
                     .map(|(_, name)| name.to_string())
                     .collect::<Vec<_>>()
                     .join(", "),
+                if have_inaccessible_fields { ", .." } else { "" },
                 postfix,
             ),
             Applicability::MachineApplicable,
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 8f8514cadb7..ca6828cfdf6 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -291,10 +291,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
         self.visit_body(body);
         self.visit_region_obligations(body_id.hir_id);
 
-        self.constrain_opaque_types(
-            &self.fcx.opaque_types.borrow(),
-            self.outlives_environment.free_region_map(),
-        );
+        self.constrain_opaque_types(self.outlives_environment.free_region_map());
     }
 
     fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index e6eac16667d..959ab69a679 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -498,7 +498,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     }
 
     fn visit_opaque_types(&mut self, span: Span) {
-        for &(opaque_type_key, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
+        let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
+        for (opaque_type_key, opaque_defn) in opaque_types {
             let hir_id =
                 self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
             let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 96b3fa9aa01..b9483d6f987 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -190,8 +190,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
                 // Try to use the segment resolution if it is valid, otherwise we
                 // default to the path resolution.
                 let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
+                use def::CtorOf;
                 let generics = match res {
-                    Res::Def(DefKind::Ctor(..), def_id) => {
+                    Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx.generics_of(
+                        tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap(),
+                    ),
+                    Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
                         tcx.generics_of(tcx.parent(def_id).unwrap())
                     }
                     // Other `DefKind`s don't have generics and would ICE when calling
@@ -200,7 +204,6 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
                         DefKind::Struct
                         | DefKind::Union
                         | DefKind::Enum
-                        | DefKind::Variant
                         | DefKind::Trait
                         | DefKind::OpaqueTy
                         | DefKind::TyAlias