about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock3
-rw-r--r--src/libcore/iter/traits/collect.rs1
-rw-r--r--src/librustc/error_codes.rs1
-rw-r--r--src/librustc/hir/lowering.rs2
-rw-r--r--src/librustc/hir/lowering/item.rs25
-rw-r--r--src/librustc/hir/mod.rs16
-rw-r--r--src/librustc/hir/print.rs4
-rw-r--r--src/librustc/ich/impls_syntax.rs10
-rw-r--r--src/librustc/infer/error_reporting/mod.rs6
-rw-r--r--src/librustc/ty/layout.rs5
-rw-r--r--src/librustc/ty/print/obsolete.rs26
-rw-r--r--src/librustc/ty/print/pretty.rs25
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs6
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs6
-rw-r--r--src/librustc_codegen_ssa/debuginfo/type_names.rs14
-rw-r--r--src/librustc_interface/Cargo.toml4
-rw-r--r--src/librustc_lint/array_into_iter.rs91
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_lint/types.rs36
-rw-r--r--src/librustc_metadata/cstore_impl.rs4
-rw-r--r--src/librustc_metadata/decoder.rs12
-rw-r--r--src/librustc_metadata/encoder.rs64
-rw-r--r--src/librustc_metadata/schema.rs9
-rw-r--r--src/librustc_mir/hair/constant.rs5
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs5
-rw-r--r--src/librustc_save_analysis/Cargo.toml1
-rw-r--r--src/librustc_save_analysis/sig.rs26
-rw-r--r--src/librustc_target/abi/mod.rs40
-rw-r--r--src/librustc_typeck/check/cast.rs5
-rw-r--r--src/librustc_typeck/check/expr.rs36
-rw-r--r--src/librustc_typeck/check/mod.rs157
-rw-r--r--src/librustc_typeck/collect.rs70
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/clean/mod.rs19
-rw-r--r--src/libsyntax/Cargo.toml1
-rw-r--r--src/libsyntax/ast.rs115
-rw-r--r--src/libsyntax/error_codes.rs1
-rw-r--r--src/libsyntax/feature_gate/check.rs75
-rw-r--r--src/libsyntax/parse/literal.rs23
-rw-r--r--src/libsyntax/parse/parser.rs70
-rw-r--r--src/libsyntax/parse/parser/expr.rs25
-rw-r--r--src/libsyntax/parse/parser/generics.rs5
-rw-r--r--src/libsyntax/parse/parser/item.rs29
-rw-r--r--src/libsyntax/parse/parser/pat.rs16
-rw-r--r--src/libsyntax/parse/parser/path.rs4
-rw-r--r--src/libsyntax/parse/token.rs11
-rw-r--r--src/libsyntax/print/pprust.rs13
-rw-r--r--src/libsyntax/print/pprust/tests.rs7
-rw-r--r--src/libsyntax/sess.rs82
-rw-r--r--src/libsyntax_expand/Cargo.toml1
-rw-r--r--src/libsyntax_expand/mbe/macro_rules.rs17
-rw-r--r--src/libsyntax_ext/concat.rs3
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs31
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/libtest/tests.rs4
-rw-r--r--src/test/ui/feature-gated-feature-in-macro-arg.stderr8
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.stderr272
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr8
-rw-r--r--src/test/ui/feature-gates/feature-gate-intrinsics.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr16
-rw-r--r--src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr8
-rw-r--r--src/test/ui/impl-trait/trait_type.stderr2
-rw-r--r--src/test/ui/issues/issue-3344.stderr2
-rw-r--r--src/test/ui/iterators/into-iter-on-arrays-lint.fixed33
-rw-r--r--src/test/ui/iterators/into-iter-on-arrays-lint.rs33
-rw-r--r--src/test/ui/iterators/into-iter-on-arrays-lint.stderr37
-rw-r--r--src/test/ui/missing/missing-items/m2.stderr6
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.rs4
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.stderr4
-rw-r--r--src/test/ui/parser/extern-abi-from-mac-literal-frag.rs26
-rw-r--r--src/test/ui/parser/extern-abi-raw-strings.rs13
-rw-r--r--src/test/ui/parser/extern-abi-string-escaping.rs13
-rw-r--r--src/test/ui/parser/extern-abi-syntactic.rs17
-rw-r--r--src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs14
-rw-r--r--src/test/ui/span/impl-wrong-item-for-trait.stderr2
-rw-r--r--src/test/ui/span/issue-23729.stderr2
-rw-r--r--src/test/ui/span/issue-23827.stderr2
-rw-r--r--src/test/ui/span/issue-24356.stderr2
-rw-r--r--src/test/ui/suggestions/missing-trait-item.fixed20
-rw-r--r--src/test/ui/suggestions/missing-trait-item.rs16
-rw-r--r--src/test/ui/suggestions/missing-trait-item.stderr25
82 files changed, 1141 insertions, 734 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a6dca2048d4..0f770f3eadb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3762,7 +3762,6 @@ dependencies = [
  "rustc",
  "rustc_codegen_utils",
  "rustc_data_structures",
- "rustc_target",
  "serde_json",
  "syntax",
  "syntax_pos",
@@ -4362,7 +4361,6 @@ dependencies = [
  "rustc_errors",
  "rustc_index",
  "rustc_lexer",
- "rustc_target",
  "scoped-tls",
  "serialize",
  "smallvec 1.0.0",
@@ -4380,7 +4378,6 @@ dependencies = [
  "rustc_errors",
  "rustc_index",
  "rustc_lexer",
- "rustc_target",
  "scoped-tls",
  "serialize",
  "smallvec 1.0.0",
diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs
index 00a86417058..bbdb169cac0 100644
--- a/src/libcore/iter/traits/collect.rs
+++ b/src/libcore/iter/traits/collect.rs
@@ -205,6 +205,7 @@ pub trait FromIterator<A>: Sized {
 ///         .collect()
 /// }
 /// ```
+#[rustc_diagnostic_item = "IntoIterator"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait IntoIterator {
     /// The type of the elements being iterated over.
diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs
index 18d98efebd4..f40b892a06b 100644
--- a/src/librustc/error_codes.rs
+++ b/src/librustc/error_codes.rs
@@ -2336,6 +2336,7 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
     E0657, // `impl Trait` can only capture lifetimes bound at the fn level
     E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
     E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
+    E0703, // invalid ABI
 //  E0707, // multiple elided lifetimes used in arguments of `async fn`
     E0708, // `async` non-`move` closures with parameters are not currently
            // supported
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 230fbb16b87..6344c7a233c 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1216,7 +1216,7 @@ impl<'a> LoweringContext<'a> {
                                     ImplTraitContext::disallowed(),
                                 ),
                                 unsafety: this.lower_unsafety(f.unsafety),
-                                abi: f.abi,
+                                abi: this.lower_abi(f.abi),
                                 decl: this.lower_fn_decl(&f.decl, None, false, None),
                                 param_names: this.lower_fn_params_to_names(&f.decl),
                             }))
diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs
index f1b999cdd6f..5fe463d783f 100644
--- a/src/librustc/hir/lowering/item.rs
+++ b/src/librustc/hir/lowering/item.rs
@@ -12,6 +12,7 @@ use crate::hir::def::{Res, DefKind};
 use crate::util::nodemap::NodeMap;
 
 use rustc_data_structures::thin_vec::ThinVec;
+use rustc_target::spec::abi;
 
 use std::collections::BTreeSet;
 use smallvec::SmallVec;
@@ -735,7 +736,7 @@ impl LoweringContext<'_> {
 
     fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod {
         hir::ForeignMod {
-            abi: fm.abi,
+            abi: self.lower_abi(fm.abi),
             items: fm.items
                 .iter()
                 .map(|x| self.lower_foreign_item(x))
@@ -1291,10 +1292,30 @@ impl LoweringContext<'_> {
             unsafety: self.lower_unsafety(h.unsafety),
             asyncness: self.lower_asyncness(h.asyncness.node),
             constness: self.lower_constness(h.constness),
-            abi: h.abi,
+            abi: self.lower_abi(h.abi),
         }
     }
 
+    pub(super) fn lower_abi(&mut self, abi: Abi) -> abi::Abi {
+        abi::lookup(&abi.symbol.as_str()).unwrap_or_else(|| {
+            self.error_on_invalid_abi(abi);
+            abi::Abi::Rust
+        })
+    }
+
+    fn error_on_invalid_abi(&self, abi: Abi) {
+        struct_span_err!(
+            self.sess,
+            abi.span,
+            E0703,
+            "invalid ABI: found `{}`",
+            abi.symbol
+        )
+        .span_label(abi.span, "invalid ABI")
+        .help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
+        .emit();
+    }
+
     pub(super) fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
         match u {
             Unsafety::Unsafe => hir::Unsafety::Unsafe,
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d6f7ba6b973..d409ca6f3c5 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1075,6 +1075,13 @@ impl Mutability {
             MutImmutable => MutMutable,
         }
     }
+
+    pub fn prefix_str(&self) -> &'static str {
+        match self {
+            MutMutable => "mut ",
+            MutImmutable => "",
+        }
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
@@ -2184,6 +2191,15 @@ pub enum Unsafety {
     Normal,
 }
 
+impl Unsafety {
+    pub fn prefix_str(&self) -> &'static str {
+        match self {
+            Unsafety::Unsafe => "unsafe ",
+            Unsafety::Normal => "",
+        }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum Constness {
     Const,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 328d475be06..a25c111b598 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1734,9 +1734,7 @@ impl<'a> State<'a> {
                     _ => false,
                 };
                 self.s.word("&");
-                if mutbl == hir::MutMutable {
-                    self.s.word("mut ");
-                }
+                self.s.word(mutbl.prefix_str());
                 if is_range_inner {
                     self.popen();
                 }
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index aa147462e3d..2201c4b0980 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -124,7 +124,6 @@ for ::syntax::attr::StabilityLevel {
 
 impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason, suggestion });
 
-
 impl_stable_hash_for!(enum ::syntax::attr::IntType {
     SignedInt(int_ty),
     UnsignedInt(uint_ty)
@@ -136,6 +135,11 @@ impl_stable_hash_for!(enum ::syntax::ast::LitIntType {
     Unsuffixed
 });
 
+impl_stable_hash_for!(enum ::syntax::ast::LitFloatType {
+    Suffixed(float_ty),
+    Unsuffixed
+});
+
 impl_stable_hash_for!(struct ::syntax::ast::Lit {
     kind,
     token,
@@ -148,8 +152,7 @@ impl_stable_hash_for!(enum ::syntax::ast::LitKind {
     Byte(value),
     Char(value),
     Int(value, lit_int_type),
-    Float(value, float_ty),
-    FloatUnsuffixed(value),
+    Float(value, lit_float_type),
     Bool(value),
     Err(value)
 });
@@ -159,6 +162,7 @@ impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
 impl_stable_hash_for!(enum ::syntax::ast::IntTy { Isize, I8, I16, I32, I64, I128 });
 impl_stable_hash_for!(enum ::syntax::ast::UintTy { Usize, U8, U16, U32, U64, U128 });
 impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 });
+impl_stable_hash_for!(enum ::rustc_target::abi::FloatTy { F32, F64 });
 impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal });
 impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst });
 impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final });
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index e238c966122..38edef50c96 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -897,11 +897,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             } else {
                 r.push(' ');
             }
-            s.push_highlighted(format!(
-                "&{}{}",
-                r,
-                if mutbl == hir::MutMutable { "mut " } else { "" }
-            ));
+            s.push_highlighted(format!("&{}{}", r, mutbl.prefix_str()));
             s.push_normal(ty.to_string());
         }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 95040135eb7..60aab6b6aa9 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -538,7 +538,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             ty::Uint(ity) => {
                 scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false))
             }
-            ty::Float(fty) => scalar(Float(fty)),
+            ty::Float(fty) => scalar(Float(match fty {
+                ast::FloatTy::F32 => FloatTy::F32,
+                ast::FloatTy::F64 => FloatTy::F64,
+            })),
             ty::FnPtr(_) => {
                 let mut ptr = scalar_unit(Pointer);
                 ptr.valid_range = 1..=*ptr.valid_range.end();
diff --git a/src/librustc/ty/print/obsolete.rs b/src/librustc/ty/print/obsolete.rs
index e72916de6a9..ddbba972e51 100644
--- a/src/librustc/ty/print/obsolete.rs
+++ b/src/librustc/ty/print/obsolete.rs
@@ -12,7 +12,6 @@ use rustc::ty::{self, Const, Instance, Ty, TyCtxt};
 use rustc::{bug, hir};
 use std::fmt::Write;
 use std::iter;
-use syntax::ast;
 
 /// Same as `unique_type_name()` but with the result pushed onto the given
 /// `output` parameter.
@@ -39,20 +38,9 @@ impl DefPathBasedNames<'tcx> {
             ty::Char => output.push_str("char"),
             ty::Str => output.push_str("str"),
             ty::Never => output.push_str("!"),
-            ty::Int(ast::IntTy::Isize) => output.push_str("isize"),
-            ty::Int(ast::IntTy::I8) => output.push_str("i8"),
-            ty::Int(ast::IntTy::I16) => output.push_str("i16"),
-            ty::Int(ast::IntTy::I32) => output.push_str("i32"),
-            ty::Int(ast::IntTy::I64) => output.push_str("i64"),
-            ty::Int(ast::IntTy::I128) => output.push_str("i128"),
-            ty::Uint(ast::UintTy::Usize) => output.push_str("usize"),
-            ty::Uint(ast::UintTy::U8) => output.push_str("u8"),
-            ty::Uint(ast::UintTy::U16) => output.push_str("u16"),
-            ty::Uint(ast::UintTy::U32) => output.push_str("u32"),
-            ty::Uint(ast::UintTy::U64) => output.push_str("u64"),
-            ty::Uint(ast::UintTy::U128) => output.push_str("u128"),
-            ty::Float(ast::FloatTy::F32) => output.push_str("f32"),
-            ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
+            ty::Int(ty) => output.push_str(ty.name_str()),
+            ty::Uint(ty) => output.push_str(ty.name_str()),
+            ty::Float(ty) => output.push_str(ty.name_str()),
             ty::Adt(adt_def, substs) => {
                 self.push_def_path(adt_def.did, output);
                 self.push_generic_params(substs, iter::empty(), output, debug);
@@ -80,9 +68,7 @@ impl DefPathBasedNames<'tcx> {
             }
             ty::Ref(_, inner_type, mutbl) => {
                 output.push('&');
-                if mutbl == hir::MutMutable {
-                    output.push_str("mut ");
-                }
+                output.push_str(mutbl.prefix_str());
 
                 self.push_type_name(inner_type, output, debug);
             }
@@ -114,9 +100,7 @@ impl DefPathBasedNames<'tcx> {
             ty::Foreign(did) => self.push_def_path(did, output),
             ty::FnDef(..) | ty::FnPtr(_) => {
                 let sig = t.fn_sig(self.tcx);
-                if sig.unsafety() == hir::Unsafety::Unsafe {
-                    output.push_str("unsafe ");
-                }
+                output.push_str(sig.unsafety().prefix_str());
 
                 let abi = sig.abi();
                 if abi != ::rustc_target::spec::abi::Abi::Rust {
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 8a98a5d8361..4c75e474011 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -466,9 +466,9 @@ pub trait PrettyPrinter<'tcx>:
         match ty.kind {
             ty::Bool => p!(write("bool")),
             ty::Char => p!(write("char")),
-            ty::Int(t) => p!(write("{}", t.ty_to_string())),
-            ty::Uint(t) => p!(write("{}", t.ty_to_string())),
-            ty::Float(t) => p!(write("{}", t.ty_to_string())),
+            ty::Int(t) => p!(write("{}", t.name_str())),
+            ty::Uint(t) => p!(write("{}", t.name_str())),
+            ty::Float(t) => p!(write("{}", t.name_str())),
             ty::RawPtr(ref tm) => {
                 p!(write("*{} ", match tm.mutbl {
                     hir::MutMutable => "mut",
@@ -895,10 +895,11 @@ pub trait PrettyPrinter<'tcx>:
                 let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
                 let max = truncate(u128::max_value(), bit_size);
 
+                let ui_str = ui.name_str();
                 if data == max {
-                    p!(write("std::{}::MAX", ui))
+                    p!(write("std::{}::MAX", ui_str))
                 } else {
-                    p!(write("{}{}", data, ui))
+                    p!(write("{}{}", data, ui_str))
                 };
             },
             (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => {
@@ -911,10 +912,11 @@ pub trait PrettyPrinter<'tcx>:
                 let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
                     .unwrap()
                     .size;
+                let i_str = i.name_str();
                 match data {
-                    d if d == min => p!(write("std::{}::MIN", i)),
-                    d if d == max => p!(write("std::{}::MAX", i)),
-                    _ => p!(write("{}{}", sign_extend(data, size) as i128, i))
+                    d if d == min => p!(write("std::{}::MIN", i_str)),
+                    d if d == max => p!(write("std::{}::MAX", i_str)),
+                    _ => p!(write("{}{}", sign_extend(data, size) as i128, i_str))
                 }
             },
             (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) =>
@@ -1666,8 +1668,7 @@ define_print_and_forward_display! {
     }
 
     ty::TypeAndMut<'tcx> {
-        p!(write("{}", if self.mutbl == hir::MutMutable { "mut " } else { "" }),
-            print(self.ty))
+        p!(write("{}", self.mutbl.prefix_str()), print(self.ty))
     }
 
     ty::ExistentialTraitRef<'tcx> {
@@ -1693,9 +1694,7 @@ define_print_and_forward_display! {
     }
 
     ty::FnSig<'tcx> {
-        if self.unsafety == hir::Unsafety::Unsafe {
-            p!(write("unsafe "));
-        }
+        p!(write("{}", self.unsafety.prefix_str()));
 
         if self.abi != Abi::Rust {
             p!(write("extern {} ", self.abi));
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index f0148a21ae6..5f18bb1700c 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -843,13 +843,13 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
         ty::Bool => ("bool", DW_ATE_boolean),
         ty::Char => ("char", DW_ATE_unsigned_char),
         ty::Int(int_ty) => {
-            (int_ty.ty_to_string(), DW_ATE_signed)
+            (int_ty.name_str(), DW_ATE_signed)
         },
         ty::Uint(uint_ty) => {
-            (uint_ty.ty_to_string(), DW_ATE_unsigned)
+            (uint_ty.name_str(), DW_ATE_unsigned)
         },
         ty::Float(float_ty) => {
-            (float_ty.ty_to_string(), DW_ATE_float)
+            (float_ty.name_str(), DW_ATE_float)
         },
         _ => bug!("debuginfo::basic_type_metadata - t is invalid type")
     };
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 1bce34abe55..a4c3b42f51e 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -18,8 +18,8 @@ use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
 use rustc::mir::interpret::GlobalId;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc::hir;
-use syntax::ast::{self, FloatTy};
-use rustc_target::abi::HasDataLayout;
+use rustc_target::abi::{FloatTy, HasDataLayout};
+use syntax::ast;
 
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::traits::*;
@@ -1335,7 +1335,7 @@ fn generic_simd_intrinsic(
             },
             ty::Float(f) => {
                 return_error!("unsupported element type `{}` of floating-point vector `{}`",
-                              f, in_ty);
+                              f.name_str(), in_ty);
             },
             _ => {
                 return_error!("`{}` is not a floating-point type", in_ty);
diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs
index 166a74fe487..f40b942b1e3 100644
--- a/src/librustc_codegen_ssa/debuginfo/type_names.rs
+++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs
@@ -37,9 +37,9 @@ pub fn push_debuginfo_type_name<'tcx>(
         ty::Char => output.push_str("char"),
         ty::Str => output.push_str("str"),
         ty::Never => output.push_str("!"),
-        ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()),
-        ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
-        ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()),
+        ty::Int(int_ty) => output.push_str(int_ty.name_str()),
+        ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()),
+        ty::Float(float_ty) => output.push_str(float_ty.name_str()),
         ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
         ty::Adt(def, substs) => {
             push_item_name(tcx, def.did, qualified, output);
@@ -76,9 +76,7 @@ pub fn push_debuginfo_type_name<'tcx>(
             if !cpp_like_names {
                 output.push('&');
             }
-            if mutbl == hir::MutMutable {
-                output.push_str("mut ");
-            }
+            output.push_str(mutbl.prefix_str());
 
             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
 
@@ -140,9 +138,7 @@ pub fn push_debuginfo_type_name<'tcx>(
 
 
             let sig = t.fn_sig(tcx);
-            if sig.unsafety() == hir::Unsafety::Unsafe {
-                output.push_str("unsafe ");
-            }
+            output.push_str(sig.unsafety().prefix_str());
 
             let abi = sig.abi();
             if abi != rustc_target::spec::abi::Abi::Rust {
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 98e4f974a9f..35b93db1d65 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -27,7 +27,6 @@ rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_passes = { path = "../librustc_passes" }
-rustc_target = { path = "../librustc_target" }
 rustc_typeck = { path = "../librustc_typeck" }
 rustc_lint = { path = "../librustc_lint" }
 rustc_errors = { path = "../librustc_errors" }
@@ -36,3 +35,6 @@ rustc_privacy = { path = "../librustc_privacy" }
 rustc_resolve = { path = "../librustc_resolve" }
 tempfile = "3.0.5"
 once_cell = "1"
+
+[dev-dependencies]
+rustc_target = { path = "../librustc_target" }
diff --git a/src/librustc_lint/array_into_iter.rs b/src/librustc_lint/array_into_iter.rs
new file mode 100644
index 00000000000..e73414174fb
--- /dev/null
+++ b/src/librustc_lint/array_into_iter.rs
@@ -0,0 +1,91 @@
+use crate::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::{
+    lint::FutureIncompatibleInfo,
+    hir,
+    ty::{
+        self,
+        adjustment::{Adjust, Adjustment},
+    },
+};
+use syntax::{
+    errors::Applicability,
+    symbol::sym,
+};
+
+
+declare_lint! {
+    pub ARRAY_INTO_ITER,
+    Warn,
+    "detects calling `into_iter` on arrays",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>",
+        edition: None,
+    };
+}
+
+declare_lint_pass!(
+    /// Checks for instances of calling `into_iter` on arrays.
+    ArrayIntoIter => [ARRAY_INTO_ITER]
+);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIntoIter {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
+        // We only care about method call expressions.
+        if let hir::ExprKind::MethodCall(call, span, args) = &expr.kind {
+            if call.ident.name != sym::into_iter {
+                return;
+            }
+
+            // Check if the method call actually calls the libcore
+            // `IntoIterator::into_iter`.
+            let def_id = cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+            match cx.tcx.trait_of_item(def_id) {
+                Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {},
+                _ => return,
+            };
+
+            // As this is a method call expression, we have at least one
+            // argument.
+            let receiver_arg = &args[0];
+
+            // Test if the original `self` type is an array type.
+            match cx.tables.expr_ty(receiver_arg).kind {
+                ty::Array(..) => {}
+                _ => return,
+            }
+
+            // Make sure that the first adjustment is an autoref coercion.
+            match cx.tables.expr_adjustments(receiver_arg).get(0) {
+                Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
+                _ => return,
+            }
+
+            // Emit lint diagnostic.
+            let target = match cx.tables.expr_ty_adjusted(receiver_arg).kind {
+                ty::Ref(_, ty::TyS { kind: ty::Array(..), ..}, _) => "[T; N]",
+                ty::Ref(_, ty::TyS { kind: ty::Slice(..), ..}, _) => "[T]",
+
+                // We know the original first argument type is an array type,
+                // we know that the first adjustment was an autoref coercion
+                // and we know that `IntoIterator` is the trait involved. The
+                // array cannot be coerced to something other than a reference
+                // to an array or to a slice.
+                _ => bug!("array type coerced to something other than array or slice"),
+            };
+            let msg = format!(
+                "this method call currently resolves to `<&{} as IntoIterator>::into_iter` (due \
+                    to autoref coercions), but that might change in the future when \
+                    `IntoIterator` impls for arrays are added.",
+                target,
+            );
+            cx.struct_span_lint(ARRAY_INTO_ITER, *span, &msg)
+                .span_suggestion(
+                    call.ident.span,
+                    "use `.iter()` instead of `.into_iter()` to avoid ambiguity",
+                    "iter".into(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
+    }
+}
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index a47980c5ead..d1dc1d0fb68 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -22,6 +22,7 @@
 #[macro_use]
 extern crate rustc;
 
+mod array_into_iter;
 mod error_codes;
 mod nonstandard_style;
 mod redundant_semicolon;
@@ -57,6 +58,7 @@ use types::*;
 use unused::*;
 use non_ascii_idents::*;
 use rustc::lint::internal::*;
+use array_into_iter::ArrayIntoIter;
 
 /// Useful for other parts of the compiler.
 pub use builtin::SoftLints;
@@ -131,6 +133,8 @@ macro_rules! late_lint_passes {
             // FIXME: Turn the computation of types which implement Debug into a query
             // and change this to a module lint pass
             MissingDebugImplementations: MissingDebugImplementations::default(),
+
+            ArrayIntoIter: ArrayIntoIter,
         ]);
     )
 }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index f2ad400d5dd..65e0940920b 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -68,7 +68,7 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>(
     max: u128,
     expr: &'tcx hir::Expr,
     parent_expr: &'tcx hir::Expr,
-    ty: impl std::fmt::Debug,
+    ty: &str,
 ) -> bool {
     // We only want to handle exclusive (`..`) ranges,
     // which are represented as `ExprKind::Struct`.
@@ -83,15 +83,15 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>(
             let mut err = cx.struct_span_lint(
                 OVERFLOWING_LITERALS,
                 parent_expr.span,
-                &format!("range endpoint is out of range for `{:?}`", ty),
+                &format!("range endpoint is out of range for `{}`", ty),
             );
             if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
                 use ast::{LitKind, LitIntType};
                 // We need to preserve the literal's suffix,
                 // as it may determine typing information.
                 let suffix = match lit.node {
-                    LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s),
-                    LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s),
+                    LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s.name_str()),
+                    LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s.name_str()),
                     LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(),
                     _ => bug!(),
                 };
@@ -161,11 +161,11 @@ fn report_bin_hex_error(
     let (t, actually) = match ty {
         attr::IntType::SignedInt(t) => {
             let actually = sign_extend(val, size) as i128;
-            (format!("{:?}", t), actually.to_string())
+            (t.name_str(), actually.to_string())
         }
         attr::IntType::UnsignedInt(t) => {
             let actually = truncate(val, size);
-            (format!("{:?}", t), actually.to_string())
+            (t.name_str(), actually.to_string())
         }
     };
     let mut err = cx.struct_span_lint(
@@ -204,7 +204,7 @@ fn report_bin_hex_error(
 //  - `uX` => `uY`
 //
 // No suggestion for: `isize`, `usize`.
-fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<String> {
+fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> {
     use syntax::ast::IntTy::*;
     use syntax::ast::UintTy::*;
     macro_rules! find_fit {
@@ -215,10 +215,10 @@ fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<String> {
                 match $ty {
                     $($type => {
                         $(if !negative && val <= uint_ty_range($utypes).1 {
-                            return Some(format!("{:?}", $utypes))
+                            return Some($utypes.name_str())
                         })*
                         $(if val <= int_ty_range($itypes).1 as u128 + _neg {
-                            return Some(format!("{:?}", $itypes))
+                            return Some($itypes.name_str())
                         })*
                         None
                     },)+
@@ -281,7 +281,7 @@ fn lint_int_literal<'a, 'tcx>(
         if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
             if let hir::ExprKind::Struct(..) = par_e.kind {
                 if is_range_literal(cx.sess(), par_e)
-                    && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t)
+                    && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
                 {
                     // The overflowing literal lint was overridden.
                     return;
@@ -292,7 +292,7 @@ fn lint_int_literal<'a, 'tcx>(
         cx.span_lint(
             OVERFLOWING_LITERALS,
             e.span,
-            &format!("literal out of range for `{:?}`", t),
+            &format!("literal out of range for `{}`", t.name_str()),
         );
     }
 }
@@ -338,6 +338,7 @@ fn lint_uint_literal<'a, 'tcx>(
                 }
                 hir::ExprKind::Struct(..)
                     if is_range_literal(cx.sess(), par_e) => {
+                        let t = t.name_str();
                         if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
                             // The overflowing literal lint was overridden.
                             return;
@@ -353,7 +354,7 @@ fn lint_uint_literal<'a, 'tcx>(
         cx.span_lint(
             OVERFLOWING_LITERALS,
             e.span,
-            &format!("literal out of range for `{:?}`", t),
+            &format!("literal out of range for `{}`", t.name_str()),
         );
     }
 }
@@ -379,8 +380,7 @@ fn lint_literal<'a, 'tcx>(
         }
         ty::Float(t) => {
             let is_infinite = match lit.node {
-                ast::LitKind::Float(v, _) |
-                ast::LitKind::FloatUnsuffixed(v) => {
+                ast::LitKind::Float(v, _) => {
                     match t {
                         ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
                         ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
@@ -389,9 +389,11 @@ fn lint_literal<'a, 'tcx>(
                 _ => bug!(),
             };
             if is_infinite == Ok(true) {
-                cx.span_lint(OVERFLOWING_LITERALS,
-                             e.span,
-                             &format!("literal out of range for `{:?}`", t));
+                cx.span_lint(
+                    OVERFLOWING_LITERALS,
+                    e.span,
+                    &format!("literal out of range for `{}`", t.name_str()),
+                );
             }
         }
         _ => {}
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index c5f830c0d04..b01b99ffcfb 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -95,8 +95,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     generics_of => {
         tcx.arena.alloc(cdata.get_generics(def_id.index, tcx.sess))
     }
-    predicates_of => { cdata.get_predicates(def_id.index, tcx) }
-    predicates_defined_on => { cdata.get_predicates_defined_on(def_id.index, tcx) }
+    explicit_predicates_of => { cdata.get_explicit_predicates(def_id.index, tcx) }
+    inferred_outlives_of => { cdata.get_inferred_outlives(def_id.index, tcx) }
     super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
     trait_def => {
         tcx.arena.alloc(cdata.get_trait_def(def_id.index, tcx.sess))
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index c5954e1ea1d..771d01a4b6a 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -658,20 +658,22 @@ impl<'a, 'tcx> CrateMetadata {
         tcx.alloc_adt_def(did, adt_kind, variants, repr)
     }
 
-    crate fn get_predicates(
+    crate fn get_explicit_predicates(
         &self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
-        self.root.per_def.predicates.get(self, item_id).unwrap().decode((self, tcx))
+        self.root.per_def.explicit_predicates.get(self, item_id).unwrap().decode((self, tcx))
     }
 
-    crate fn get_predicates_defined_on(
+    crate fn get_inferred_outlives(
         &self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
-    ) -> ty::GenericPredicates<'tcx> {
-        self.root.per_def.predicates_defined_on.get(self, item_id).unwrap().decode((self, tcx))
+    ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+        self.root.per_def.inferred_outlives.get(self, item_id).map(|predicates| {
+            predicates.decode((self, tcx))
+        }).unwrap_or_default()
     }
 
     crate fn get_super_predicates(
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index de00e9920e6..618d342f6fe 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -76,8 +76,8 @@ struct PerDefTables<'tcx> {
     inherent_impls: PerDefTable<Lazy<[DefIndex]>>,
     variances: PerDefTable<Lazy<[ty::Variance]>>,
     generics: PerDefTable<Lazy<ty::Generics>>,
-    predicates: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>,
-    predicates_defined_on: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>,
+    explicit_predicates: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>,
+    inferred_outlives: PerDefTable<Lazy<&'tcx [(ty::Predicate<'tcx>, Span)]>>,
     super_predicates: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>,
 
     mir: PerDefTable<Lazy<mir::Body<'tcx>>>,
@@ -524,8 +524,8 @@ impl<'tcx> EncodeContext<'tcx> {
             inherent_impls: self.per_def.inherent_impls.encode(&mut self.opaque),
             variances: self.per_def.variances.encode(&mut self.opaque),
             generics: self.per_def.generics.encode(&mut self.opaque),
-            predicates: self.per_def.predicates.encode(&mut self.opaque),
-            predicates_defined_on: self.per_def.predicates_defined_on.encode(&mut self.opaque),
+            explicit_predicates: self.per_def.explicit_predicates.encode(&mut self.opaque),
+            inferred_outlives: self.per_def.inferred_outlives.encode(&mut self.opaque),
             super_predicates: self.per_def.super_predicates.encode(&mut self.opaque),
 
             mir: self.per_def.mir.encode(&mut self.opaque),
@@ -675,7 +675,8 @@ impl EncodeContext<'tcx> {
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
         self.encode_optimized_mir(def_id);
         self.encode_promoted_mir(def_id);
     }
@@ -718,7 +719,8 @@ impl EncodeContext<'tcx> {
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
         self.encode_optimized_mir(def_id);
         self.encode_promoted_mir(def_id);
     }
@@ -776,7 +778,8 @@ impl EncodeContext<'tcx> {
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
     }
 
     fn encode_struct_ctor(&mut self, adt_def_id: DefId, def_id: DefId) {
@@ -819,7 +822,8 @@ impl EncodeContext<'tcx> {
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
         self.encode_optimized_mir(def_id);
         self.encode_promoted_mir(def_id);
     }
@@ -829,15 +833,18 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.generics[def_id] <- self.tcx.generics_of(def_id));
     }
 
-    fn encode_predicates(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_predicates({:?})", def_id);
-        record!(self.per_def.predicates[def_id] <- self.tcx.predicates_of(def_id));
+    fn encode_explicit_predicates(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_explicit_predicates({:?})", def_id);
+        record!(self.per_def.explicit_predicates[def_id] <-
+            self.tcx.explicit_predicates_of(def_id));
     }
 
-    fn encode_predicates_defined_on(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_predicates_defined_on({:?})", def_id);
-        record!(self.per_def.predicates_defined_on[def_id] <-
-            self.tcx.predicates_defined_on(def_id))
+    fn encode_inferred_outlives(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_inferred_outlives({:?})", def_id);
+        let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
+        if !inferred_outlives.is_empty() {
+            record!(self.per_def.inferred_outlives[def_id] <- inferred_outlives);
+        }
     }
 
     fn encode_super_predicates(&mut self, def_id: DefId) {
@@ -919,7 +926,8 @@ impl EncodeContext<'tcx> {
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
         self.encode_optimized_mir(def_id);
         self.encode_promoted_mir(def_id);
     }
@@ -986,7 +994,8 @@ impl EncodeContext<'tcx> {
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
         let mir = match ast_item.kind {
             hir::ImplItemKind::Const(..) => true,
             hir::ImplItemKind::Method(ref sig, _) => {
@@ -1260,22 +1269,11 @@ impl EncodeContext<'tcx> {
             hir::ItemKind::Trait(..) |
             hir::ItemKind::TraitAlias(..) => {
                 self.encode_generics(def_id);
-                self.encode_predicates(def_id);
+                self.encode_explicit_predicates(def_id);
+                self.encode_inferred_outlives(def_id);
             }
             _ => {}
         }
-        // The only time that `predicates_defined_on` is used (on
-        // an external item) is for traits, during chalk lowering,
-        // so only encode it in that case as an efficiency
-        // hack. (No reason not to expand it in the future if
-        // necessary.)
-        match item.kind {
-            hir::ItemKind::Trait(..) |
-            hir::ItemKind::TraitAlias(..) => {
-                self.encode_predicates_defined_on(def_id);
-            }
-            _ => {} // not *wrong* for other kinds of items, but not needed
-        }
         match item.kind {
             hir::ItemKind::Trait(..) |
             hir::ItemKind::TraitAlias(..) => {
@@ -1377,7 +1375,8 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
         self.encode_item_type(def_id);
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
         self.encode_optimized_mir(def_id);
         self.encode_promoted_mir(def_id);
     }
@@ -1588,7 +1587,8 @@ impl EncodeContext<'tcx> {
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
-        self.encode_predicates(def_id);
+        self.encode_explicit_predicates(def_id);
+        self.encode_inferred_outlives(def_id);
     }
 }
 
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 8bece251116..f644b726432 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -244,8 +244,13 @@ crate struct LazyPerDefTables<'tcx> {
     pub inherent_impls: Lazy!(PerDefTable<Lazy<[DefIndex]>>),
     pub variances: Lazy!(PerDefTable<Lazy<[ty::Variance]>>),
     pub generics: Lazy!(PerDefTable<Lazy<ty::Generics>>),
-    pub predicates: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
-    pub predicates_defined_on: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
+    pub explicit_predicates: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
+    // FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate`
+    // doesn't handle shorthands in its own (de)serialization impls,
+    // as it's an `enum` for which we want to derive (de)serialization,
+    // so the `ty::codec` APIs handle the whole `&'tcx [...]` at once.
+    // Also, as an optimization, a missing entry indicates an empty `&[]`.
+    pub inferred_outlives: Lazy!(PerDefTable<Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>),
     pub super_predicates: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
 
     pub mir: Lazy!(PerDefTable<Lazy!(mir::Body<'tcx>)>),
diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs
index 956716f8cea..b9e75a576ca 100644
--- a/src/librustc_mir/hair/constant.rs
+++ b/src/librustc_mir/hair/constant.rs
@@ -45,10 +45,7 @@ crate fn lit_to_const<'tcx>(
             trunc(n as u128)?
         },
         LitKind::Int(n, _) => trunc(n)?,
-        LitKind::Float(n, fty) => {
-            parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
-        }
-        LitKind::FloatUnsuffixed(n) => {
+        LitKind::Float(n, _) => {
             let fty = match ty.kind {
                 ty::Float(fty) => fty,
                 _ => bug!()
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 1ecc78ba227..477ad10460f 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -293,10 +293,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 match self.ty.kind {
                     ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
                     ty::Ref(_, _, mutbl) => {
-                        write!(f, "&")?;
-                        if mutbl == hir::MutMutable {
-                            write!(f, "mut ")?;
-                        }
+                        write!(f, "&{}", mutbl.prefix_str())?;
                     }
                     _ => bug!("{} is a bad Deref pattern type", self.ty)
                 }
diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml
index b89c83d630b..2d93585e50e 100644
--- a/src/librustc_save_analysis/Cargo.toml
+++ b/src/librustc_save_analysis/Cargo.toml
@@ -13,7 +13,6 @@ log = "0.4"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
-rustc_target = { path = "../librustc_target" }
 serde_json = "1"
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 203bd4d4167..019e92717b5 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -32,7 +32,7 @@ use rls_data::{SigElement, Signature};
 use rustc::hir::def::{Res, DefKind};
 use syntax::ast::{self, NodeId};
 use syntax::print::pprust;
-
+use syntax_pos::sym;
 
 pub fn item_signature(item: &ast::Item, scx: &SaveContext<'_, '_>) -> Option<Signature> {
     if !scx.config.signatures {
@@ -157,6 +157,12 @@ fn text_sig(text: String) -> Signature {
     }
 }
 
+fn push_abi(text: &mut String, abi: ast::Abi) {
+    if abi.symbol != sym::Rust {
+        text.push_str(&format!("extern \"{}\" ", abi.symbol));
+    }
+}
+
 impl Sig for ast::Ty {
     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
         let id = Some(self.id);
@@ -231,11 +237,7 @@ impl Sig for ast::Ty {
                 if f.unsafety == ast::Unsafety::Unsafe {
                     text.push_str("unsafe ");
                 }
-                if f.abi != rustc_target::spec::abi::Abi::Rust {
-                    text.push_str("extern");
-                    text.push_str(&f.abi.to_string());
-                    text.push(' ');
-                }
+                push_abi(&mut text, f.abi);
                 text.push_str("fn(");
 
                 let mut defs = vec![];
@@ -385,11 +387,7 @@ impl Sig for ast::Item {
                 if header.unsafety == ast::Unsafety::Unsafe {
                     text.push_str("unsafe ");
                 }
-                if header.abi != rustc_target::spec::abi::Abi::Rust {
-                    text.push_str("extern");
-                    text.push_str(&header.abi.to_string());
-                    text.push(' ');
-                }
+                push_abi(&mut text, header.abi);
                 text.push_str("fn ");
 
                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
@@ -948,11 +946,7 @@ fn make_method_signature(
     if m.header.unsafety == ast::Unsafety::Unsafe {
         text.push_str("unsafe ");
     }
-    if m.header.abi != rustc_target::spec::abi::Abi::Rust {
-        text.push_str("extern");
-        text.push_str(&m.header.abi.to_string());
-        text.push(' ');
-    }
+    push_abi(&mut text, m.header.abi);
     text.push_str("fn ");
 
     let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?;
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index fde5c5bed4d..e58caed0c99 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -3,11 +3,9 @@ pub use Primitive::*;
 
 use crate::spec::Target;
 
-use std::fmt;
 use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
 
 use rustc_index::vec::{Idx, IndexVec};
-use syntax_pos::symbol::{sym, Symbol};
 use syntax_pos::Span;
 
 pub mod call;
@@ -534,49 +532,13 @@ impl Integer {
     }
 }
 
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy,
-         PartialOrd, Ord)]
+         PartialOrd, Ord, Debug)]
 pub enum FloatTy {
     F32,
     F64,
 }
 
-impl fmt::Debug for FloatTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, f)
-    }
-}
-
-impl fmt::Display for FloatTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.ty_to_string())
-    }
-}
-
-impl FloatTy {
-    pub fn ty_to_string(self) -> &'static str {
-        match self {
-            FloatTy::F32 => "f32",
-            FloatTy::F64 => "f64",
-        }
-    }
-
-    pub fn to_symbol(self) -> Symbol {
-        match self {
-            FloatTy::F32 => sym::f32,
-            FloatTy::F64 => sym::f64,
-        }
-    }
-
-    pub fn bit_width(self) -> usize {
-        match self {
-            FloatTy::F32 => 32,
-            FloatTy::F64 => 64,
-        }
-    }
-}
-
 /// Fundamental unit of memory access and layout.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum Primitive {
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 9cbde276ae9..ded655c1ae3 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -341,10 +341,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                          tstr);
         match self.expr_ty.kind {
             ty::Ref(_, _, mt) => {
-                let mtstr = match mt {
-                    hir::MutMutable => "mut ",
-                    hir::MutImmutable => "",
-                };
+                let mtstr = mt.prefix_str();
                 if self.cast_ty.is_trait() {
                     match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
                         Ok(s) => {
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 35870abbaef..bc1189e443e 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -592,20 +592,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             cause.span,
                             target_id,
                         );
-                        let val = match ty.kind {
-                            ty::Bool => "true",
-                            ty::Char => "'a'",
-                            ty::Int(_) | ty::Uint(_) => "42",
-                            ty::Float(_) => "3.14159",
-                            ty::Error | ty::Never => return,
-                            _ => "value",
-                        };
-                        let msg = "give it a value of the expected type";
-                        let label = destination.label
-                            .map(|l| format!(" {}", l.ident))
-                            .unwrap_or_else(String::new);
-                        let sugg = format!("break{} {}", label, val);
-                        err.span_suggestion(expr.span, msg, sugg, Applicability::HasPlaceholders);
+                        if let Some(val) = ty_kind_suggestion(ty) {
+                            let label = destination.label
+                                .map(|l| format!(" {}", l.ident))
+                                .unwrap_or_else(String::new);
+                            err.span_suggestion(
+                                expr.span,
+                                "give it a value of the expected type",
+                                format!("break{} {}", label, val),
+                                Applicability::HasPlaceholders,
+                            );
+                        }
                     }, false);
                 }
             } else {
@@ -1725,3 +1722,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.tcx.mk_unit()
     }
 }
+
+pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
+    Some(match ty.kind {
+        ty::Bool => "true",
+        ty::Char => "'a'",
+        ty::Int(_) | ty::Uint(_) => "42",
+        ty::Float(_) => "3.14159",
+        ty::Error | ty::Never => return None,
+        _ => "value",
+    })
+}
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 26f04081046..fe2c7a200d2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -127,7 +127,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::source_map::{DUMMY_SP, original_sp};
-use syntax::symbol::{kw, sym};
+use syntax::symbol::{kw, sym, Ident};
 use syntax::util::parser::ExprPrecedence;
 
 use std::cell::{Cell, RefCell, Ref, RefMut};
@@ -1800,12 +1800,12 @@ fn check_specialization_validity<'tcx>(
 
 fn check_impl_items_against_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
-    impl_span: Span,
+    full_impl_span: Span,
     impl_id: DefId,
     impl_trait_ref: ty::TraitRef<'tcx>,
     impl_item_refs: &[hir::ImplItemRef],
 ) {
-    let impl_span = tcx.sess.source_map().def_span(impl_span);
+    let impl_span = tcx.sess.source_map().def_span(full_impl_span);
 
     // If the trait reference itself is erroneous (so the compilation is going
     // to fail), skip checking the items here -- the `impl_item` table in `tcx`
@@ -1925,35 +1925,132 @@ fn check_impl_items_against_trait<'tcx>(
     }
 
     if !missing_items.is_empty() {
-        let mut err = struct_span_err!(tcx.sess, impl_span, E0046,
-            "not all trait items implemented, missing: `{}`",
-            missing_items.iter()
-                .map(|trait_item| trait_item.ident.to_string())
-                .collect::<Vec<_>>().join("`, `"));
-        err.span_label(impl_span, format!("missing `{}` in implementation",
-                missing_items.iter()
-                    .map(|trait_item| trait_item.ident.to_string())
-                    .collect::<Vec<_>>().join("`, `")));
-        for trait_item in missing_items {
-            if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
-                err.span_label(span, format!("`{}` from trait", trait_item.ident));
-            } else {
-                err.note_trait_signature(trait_item.ident.to_string(),
-                                         trait_item.signature(tcx));
-            }
-        }
-        err.emit();
+        missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
     }
 
     if !invalidated_items.is_empty() {
         let invalidator = overridden_associated_type.unwrap();
-        span_err!(tcx.sess, invalidator.span, E0399,
-                  "the following trait items need to be reimplemented \
-                   as `{}` was overridden: `{}`",
-                  invalidator.ident,
-                  invalidated_items.iter()
-                                   .map(|name| name.to_string())
-                                   .collect::<Vec<_>>().join("`, `"))
+        span_err!(
+            tcx.sess,
+            invalidator.span,
+            E0399,
+            "the following trait items need to be reimplemented as `{}` was overridden: `{}`",
+            invalidator.ident,
+            invalidated_items.iter()
+                .map(|name| name.to_string())
+                .collect::<Vec<_>>().join("`, `")
+        )
+    }
+}
+
+fn missing_items_err(
+    tcx: TyCtxt<'_>,
+    impl_span: Span,
+    missing_items: &[ty::AssocItem],
+    full_impl_span: Span,
+) {
+    let missing_items_msg = missing_items.iter()
+        .map(|trait_item| trait_item.ident.to_string())
+        .collect::<Vec<_>>().join("`, `");
+
+    let mut err = struct_span_err!(
+        tcx.sess,
+        impl_span,
+        E0046,
+        "not all trait items implemented, missing: `{}`",
+        missing_items_msg
+    );
+    err.span_label(impl_span, format!("missing `{}` in implementation", missing_items_msg));
+
+    // `Span` before impl block closing brace.
+    let hi = full_impl_span.hi() - BytePos(1);
+    // Point at the place right before the closing brace of the relevant `impl` to suggest
+    // adding the associated item at the end of its body.
+    let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
+    // Obtain the level of indentation ending in `sugg_sp`.
+    let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
+    // Make the whitespace that will make the suggestion have the right indentation.
+    let padding: String = (0..indentation).map(|_| " ").collect();
+
+    for trait_item in missing_items {
+        let snippet = suggestion_signature(&trait_item, tcx);
+        let code = format!("{}{}\n{}", padding, snippet, padding);
+        let msg = format!("implement the missing item: `{}`", snippet);
+        let appl = Applicability::HasPlaceholders;
+        if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
+            err.span_label(span, format!("`{}` from trait", trait_item.ident));
+            err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
+        } else {
+            err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
+        }
+    }
+    err.emit();
+}
+
+/// Return placeholder code for the given function.
+fn fn_sig_suggestion(sig: &ty::FnSig<'_>, ident: Ident) -> String {
+    let args = sig.inputs()
+        .iter()
+        .map(|ty| Some(match ty.kind {
+            ty::Param(param) if param.name == kw::SelfUpper => "self".to_string(),
+            ty::Ref(reg, ref_ty, mutability) => {
+                let reg = match &format!("{}", reg)[..] {
+                    "'_" | "" => String::new(),
+                    reg => format!("{} ", reg),
+                };
+                match ref_ty.kind {
+                    ty::Param(param) if param.name == kw::SelfUpper => {
+                        format!("&{}{}self", reg, mutability.prefix_str())
+                    }
+                    _ => format!("_: {:?}", ty),
+                }
+            }
+            _ => format!("_: {:?}", ty),
+        }))
+        .chain(std::iter::once(if sig.c_variadic {
+            Some("...".to_string())
+        } else {
+            None
+        }))
+        .filter_map(|arg| arg)
+        .collect::<Vec<String>>()
+        .join(", ");
+    let output = sig.output();
+    let output = if !output.is_unit() {
+        format!(" -> {:?}", output)
+    } else {
+        String::new()
+    };
+
+    let unsafety = sig.unsafety.prefix_str();
+    // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
+    // not be present in the `fn` definition, not will we account for renamed
+    // lifetimes between the `impl` and the `trait`, but this should be good enough to
+    // fill in a significant portion of the missing code, and other subsequent
+    // suggestions can help the user fix the code.
+    format!("{}fn {}({}){} {{ unimplemented!() }}", unsafety, ident, args, output)
+}
+
+/// Return placeholder code for the given associated item.
+/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
+/// structured suggestion.
+fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
+    match assoc.kind {
+        ty::AssocKind::Method => {
+            // We skip the binder here because the binder would deanonymize all
+            // late-bound regions, and we don't want method signatures to show up
+            // `as for<'r> fn(&'r MyType)`.  Pretty-printing handles late-bound
+            // regions just fine, showing `fn(&MyType)`.
+            fn_sig_suggestion(tcx.fn_sig(assoc.def_id).skip_binder(), assoc.ident)
+        }
+        ty::AssocKind::Type => format!("type {} = Type;", assoc.ident),
+        // FIXME(type_alias_impl_trait): we should print bounds here too.
+        ty::AssocKind::OpaqueTy => format!("type {} = Type;", assoc.ident),
+        ty::AssocKind::Const => {
+            let ty = tcx.type_of(assoc.def_id);
+            let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
+            format!("const {}: {:?} = {};", assoc.ident, ty, val)
+        }
     }
 }
 
@@ -3660,8 +3757,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 });
                 opt_ty.unwrap_or_else(|| self.next_int_var())
             }
-            ast::LitKind::Float(_, t) => tcx.mk_mach_float(t),
-            ast::LitKind::FloatUnsuffixed(_) => {
+            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
+            ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
                 let opt_ty = expected.to_option(self).and_then(|ty| {
                     match ty.kind {
                         ty::Float(_) => Some(ty),
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 71a7b52a27b..ef84f1cb20f 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1146,10 +1146,6 @@ fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) {
     );
 }
 
-fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
-    checked_type_of(tcx, def_id, true).unwrap()
-}
-
 fn infer_placeholder_type(
     tcx: TyCtxt<'_>,
     def_id: DefId,
@@ -1193,26 +1189,14 @@ fn infer_placeholder_type(
     ty
 }
 
-/// Same as [`type_of`] but returns [`Option`] instead of failing.
-///
-/// If you want to fail anyway, you can set the `fail` parameter to true, but in this case,
-/// you'd better just call [`type_of`] directly.
-pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<'_>> {
+fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
     use rustc::hir::*;
 
-    let hir_id = match tcx.hir().as_local_hir_id(def_id) {
-        Some(hir_id) => hir_id,
-        None => {
-            if !fail {
-                return None;
-            }
-            bug!("invalid node");
-        }
-    };
+    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
 
     let icx = ItemCtxt::new(tcx, def_id);
 
-    Some(match tcx.hir().get(hir_id) {
+    match tcx.hir().get(hir_id) {
         Node::TraitItem(item) => match item.kind {
             TraitItemKind::Method(..) => {
                 let substs = InternalSubsts::identity_for_item(tcx, def_id);
@@ -1229,9 +1213,6 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
             },
             TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
             TraitItemKind::Type(_, None) => {
-                if !fail {
-                    return None;
-                }
                 span_bug!(item.span, "associated type missing default");
             }
         },
@@ -1325,9 +1306,6 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                 | ItemKind::GlobalAsm(..)
                 | ItemKind::ExternCrate(..)
                 | ItemKind::Use(..) => {
-                    if !fail {
-                        return None;
-                    }
                     span_bug!(
                         item.span,
                         "compute_type_of_item: unexpected item type: {:?}",
@@ -1365,7 +1343,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
             ..
         }) => {
             if gen.is_some() {
-                return Some(tcx.typeck_tables_of(def_id).node_type(hir_id));
+                return tcx.typeck_tables_of(def_id).node_type(hir_id);
             }
 
             let substs = InternalSubsts::identity_for_item(tcx, def_id);
@@ -1440,13 +1418,9 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                                     .map(|(index, _)| index)
                                     .next()
                             })
-                            .or_else(|| {
-                                if !fail {
-                                    None
-                                } else {
-                                    bug!("no arg matching AnonConst in path")
-                                }
-                            })?;
+                            .unwrap_or_else(|| {
+                                bug!("no arg matching AnonConst in path");
+                            });
 
                         // We've encountered an `AnonConst` in some path, so we need to
                         // figure out which generic parameter it corresponds to and return
@@ -1456,8 +1430,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                                 tcx.generics_of(tcx.parent(def_id).unwrap())
                             }
                             Res::Def(_, def_id) => tcx.generics_of(def_id),
-                            Res::Err => return Some(tcx.types.err),
-                            _ if !fail => return None,
+                            Res::Err => return tcx.types.err,
                             res => {
                                 tcx.sess.delay_span_bug(
                                     DUMMY_SP,
@@ -1466,7 +1439,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                                         res,
                                     ),
                                 );
-                                return Some(tcx.types.err);
+                                return tcx.types.err;
                             }
                         };
 
@@ -1484,9 +1457,6 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                             // probably from an extra arg where one is not needed.
                             .unwrap_or(tcx.types.err)
                     } else {
-                        if !fail {
-                            return None;
-                        }
                         tcx.sess.delay_span_bug(
                             DUMMY_SP,
                             &format!(
@@ -1494,14 +1464,11 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                                 parent_node,
                             ),
                         );
-                        return Some(tcx.types.err);
+                        return tcx.types.err;
                     }
                 }
 
                 x => {
-                    if !fail {
-                        return None;
-                    }
                     tcx.sess.delay_span_bug(
                         DUMMY_SP,
                         &format!(
@@ -1551,21 +1518,13 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                 }
                 ty
             }
-            x => {
-                if !fail {
-                    return None;
-                }
-                bug!("unexpected non-type Node::GenericParam: {:?}", x)
-            },
+            x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
         },
 
         x => {
-            if !fail {
-                return None;
-            }
             bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
         }
-    })
+    }
 }
 
 fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
@@ -2075,10 +2034,7 @@ fn explicit_predicates_of(
         }
     }
 
-    let hir_id = match tcx.hir().as_local_hir_id(def_id) {
-        Some(hir_id) => hir_id,
-        None => return tcx.predicates_of(def_id),
-    };
+    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
     let node = tcx.hir().get(hir_id);
 
     let mut is_trait = None;
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 9374113e1c9..a5a4cfa2bab 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -109,8 +109,6 @@ use util::common::time;
 use std::iter;
 
 use astconv::{AstConv, Bounds};
-pub use collect::checked_type_of;
-
 pub struct TypeAndSubsts<'tcx> {
     substs: SubstsRef<'tcx>,
     ty: Ty<'tcx>,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 32c8ca234a0..0c670e5e717 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1492,12 +1492,13 @@ impl GenericParamDefKind {
         }
     }
 
-    pub fn get_type(&self, cx: &DocContext<'_>) -> Option<Type> {
-        match *self {
-            GenericParamDefKind::Type { did, .. } => {
-                rustc_typeck::checked_type_of(cx.tcx, did, false).map(|t| t.clean(cx))
-            }
-            GenericParamDefKind::Const { ref ty, .. } => Some(ty.clone()),
+    // FIXME(eddyb) this either returns the default of a type parameter, or the
+    // type of a `const` parameter. It seems that the intention is to *visit*
+    // any embedded types, but `get_type` seems to be the wrong name for that.
+    pub fn get_type(&self) -> Option<Type> {
+        match self {
+            GenericParamDefKind::Type { default, .. } => default.clone(),
+            GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
             GenericParamDefKind::Lifetime => None,
         }
     }
@@ -1523,8 +1524,8 @@ impl GenericParamDef {
         self.kind.is_type()
     }
 
-    pub fn get_type(&self, cx: &DocContext<'_>) -> Option<Type> {
-        self.kind.get_type(cx)
+    pub fn get_type(&self) -> Option<Type> {
+        self.kind.get_type()
     }
 
     pub fn get_bounds(&self) -> Option<&[GenericBound]> {
@@ -1892,7 +1893,7 @@ fn get_real_types(
                             if !x.is_type() {
                                 continue
                             }
-                            if let Some(ty) = x.get_type(cx) {
+                            if let Some(ty) = x.get_type() {
                                 let adds = get_real_types(generics, &ty, cx, recurse + 1);
                                 if !adds.is_empty() {
                                     res.extend(adds);
diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml
index b1839cc05cd..3e17e7949ea 100644
--- a/src/libsyntax/Cargo.toml
+++ b/src/libsyntax/Cargo.toml
@@ -20,5 +20,4 @@ errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_index = { path = "../librustc_index" }
 rustc_lexer = { path = "../librustc_lexer" }
-rustc_target = { path = "../librustc_target" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 2392b809150..67d1acbccfb 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -22,7 +22,6 @@ pub use GenericArgs::*;
 pub use UnsafeSource::*;
 pub use crate::util::parser::ExprPrecedence;
 
-pub use rustc_target::abi::FloatTy;
 pub use syntax_pos::symbol::{Ident, Symbol as Name};
 
 use crate::parse::token::{self, DelimToken};
@@ -38,7 +37,6 @@ use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_index::vec::Idx;
 use rustc_serialize::{self, Decoder, Encoder};
-use rustc_target::spec::abi::Abi;
 
 #[cfg(target_arch = "x86_64")]
 use rustc_data_structures::static_assert_size;
@@ -1401,7 +1399,7 @@ pub struct Lit {
 
 // Clippy uses Hash and PartialEq
 /// Type of the integer literal based on provided suffix.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)]
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)]
 pub enum LitIntType {
     /// e.g. `42_i32`.
     Signed(IntTy),
@@ -1411,6 +1409,15 @@ pub enum LitIntType {
     Unsuffixed,
 }
 
+/// Type of the float literal based on provided suffix.
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)]
+pub enum LitFloatType {
+    /// A float literal with a suffix (`1f32` or `1E10f32`).
+    Suffixed(FloatTy),
+    /// A float literal without a suffix (`1.0 or 1.0E10`).
+    Unsuffixed,
+}
+
 /// Literal kind.
 ///
 /// E.g., `"foo"`, `42`, `12.34`, or `bool`.
@@ -1428,9 +1435,7 @@ pub enum LitKind {
     /// An integer literal (`1`).
     Int(u128, LitIntType),
     /// A float literal (`1f64` or `1E10f64`).
-    Float(Symbol, FloatTy),
-    /// A float literal without a suffix (`1.0 or 1.0E10`).
-    FloatUnsuffixed(Symbol),
+    Float(Symbol, LitFloatType),
     /// A boolean literal.
     Bool(bool),
     /// Placeholder for a literal that wasn't well-formed in some way.
@@ -1457,7 +1462,7 @@ impl LitKind {
     /// Returns `true` if this is a numeric literal.
     pub fn is_numeric(&self) -> bool {
         match *self {
-            LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => true,
+            LitKind::Int(..) | LitKind::Float(..) => true,
             _ => false,
         }
     }
@@ -1474,14 +1479,14 @@ impl LitKind {
             // suffixed variants
             LitKind::Int(_, LitIntType::Signed(..))
             | LitKind::Int(_, LitIntType::Unsigned(..))
-            | LitKind::Float(..) => true,
+            | LitKind::Float(_, LitFloatType::Suffixed(..)) => true,
             // unsuffixed variants
             LitKind::Str(..)
             | LitKind::ByteStr(..)
             | LitKind::Byte(..)
             | LitKind::Char(..)
             | LitKind::Int(_, LitIntType::Unsuffixed)
-            | LitKind::FloatUnsuffixed(..)
+            | LitKind::Float(_, LitFloatType::Unsuffixed)
             | LitKind::Bool(..)
             | LitKind::Err(..) => false,
         }
@@ -1553,7 +1558,36 @@ pub enum ImplItemKind {
     Macro(Mac),
 }
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
+pub enum FloatTy {
+    F32,
+    F64,
+}
+
+impl FloatTy {
+    pub fn name_str(self) -> &'static str {
+        match self {
+            FloatTy::F32 => "f32",
+            FloatTy::F64 => "f64",
+        }
+    }
+
+    pub fn name(self) -> Symbol {
+        match self {
+            FloatTy::F32 => sym::f32,
+            FloatTy::F64 => sym::f64,
+        }
+    }
+
+    pub fn bit_width(self) -> usize {
+        match self {
+            FloatTy::F32 => 32,
+            FloatTy::F64 => 64,
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub enum IntTy {
     Isize,
     I8,
@@ -1563,20 +1597,8 @@ pub enum IntTy {
     I128,
 }
 
-impl fmt::Debug for IntTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, f)
-    }
-}
-
-impl fmt::Display for IntTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.ty_to_string())
-    }
-}
-
 impl IntTy {
-    pub fn ty_to_string(&self) -> &'static str {
+    pub fn name_str(&self) -> &'static str {
         match *self {
             IntTy::Isize => "isize",
             IntTy::I8 => "i8",
@@ -1587,7 +1609,7 @@ impl IntTy {
         }
     }
 
-    pub fn to_symbol(&self) -> Symbol {
+    pub fn name(&self) -> Symbol {
         match *self {
             IntTy::Isize => sym::isize,
             IntTy::I8 => sym::i8,
@@ -1602,7 +1624,7 @@ impl IntTy {
         // Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types
         // are parsed as `u128`, so we wouldn't want to print an extra negative
         // sign.
-        format!("{}{}", val as u128, self.ty_to_string())
+        format!("{}{}", val as u128, self.name_str())
     }
 
     pub fn bit_width(&self) -> Option<usize> {
@@ -1617,7 +1639,7 @@ impl IntTy {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy, Debug)]
 pub enum UintTy {
     Usize,
     U8,
@@ -1628,7 +1650,7 @@ pub enum UintTy {
 }
 
 impl UintTy {
-    pub fn ty_to_string(&self) -> &'static str {
+    pub fn name_str(&self) -> &'static str {
         match *self {
             UintTy::Usize => "usize",
             UintTy::U8 => "u8",
@@ -1639,7 +1661,7 @@ impl UintTy {
         }
     }
 
-    pub fn to_symbol(&self) -> Symbol {
+    pub fn name(&self) -> Symbol {
         match *self {
             UintTy::Usize => sym::usize,
             UintTy::U8 => sym::u8,
@@ -1651,7 +1673,7 @@ impl UintTy {
     }
 
     pub fn val_to_string(&self, val: u128) -> String {
-        format!("{}{}", val, self.ty_to_string())
+        format!("{}{}", val, self.name_str())
     }
 
     pub fn bit_width(&self) -> Option<usize> {
@@ -1666,18 +1688,6 @@ impl UintTy {
     }
 }
 
-impl fmt::Debug for UintTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, f)
-    }
-}
-
-impl fmt::Display for UintTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.ty_to_string())
-    }
-}
-
 /// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
 /// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -2358,6 +2368,27 @@ impl Item {
     }
 }
 
+/// A reference to an ABI.
+///
+/// In AST our notion of an ABI is still syntactic unlike in `rustc_target::spec::abi::Abi`.
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, PartialEq)]
+pub struct Abi {
+    pub symbol: Symbol,
+    pub span: Span,
+}
+
+impl Abi {
+    pub fn new(symbol: Symbol, span: Span) -> Self {
+        Self { symbol, span }
+    }
+}
+
+impl Default for Abi {
+    fn default() -> Self {
+        Self::new(sym::Rust, DUMMY_SP)
+    }
+}
+
 /// A function header.
 ///
 /// All the information between the visibility and the name of the function is
@@ -2376,7 +2407,7 @@ impl Default for FnHeader {
             unsafety: Unsafety::Normal,
             asyncness: dummy_spanned(IsAsync::NotAsync),
             constness: dummy_spanned(Constness::NotConst),
-            abi: Abi::Rust,
+            abi: Abi::default(),
         }
     }
 }
diff --git a/src/libsyntax/error_codes.rs b/src/libsyntax/error_codes.rs
index 941df5ea570..c23c8d65a7f 100644
--- a/src/libsyntax/error_codes.rs
+++ b/src/libsyntax/error_codes.rs
@@ -540,6 +540,5 @@ equivalent in Rust would be to use macros directly.
     E0630,
     E0693, // incorrect `repr(align)` attribute format
 //  E0694, // an unknown tool name found in scoped attributes
-    E0703, // invalid ABI
     E0717, // rustc_promotable without stability attribute
 }
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index b7e75ff3a7e..5b1493ebc9b 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -18,7 +18,6 @@ use crate::tokenstream::TokenTree;
 
 use errors::{Applicability, DiagnosticBuilder, Handler};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_target::spec::abi::Abi;
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 use log::debug;
 
@@ -192,62 +191,70 @@ macro_rules! gate_feature_post {
 }
 
 impl<'a> PostExpansionVisitor<'a> {
-    fn check_abi(&self, abi: Abi, span: Span) {
-        match abi {
-            Abi::RustIntrinsic => {
+    fn check_abi(&self, abi: ast::Abi) {
+        let ast::Abi { symbol, span } = abi;
+
+        match &*symbol.as_str() {
+            // Stable
+            "Rust" |
+            "C" |
+            "cdecl" |
+            "stdcall" |
+            "fastcall" |
+            "aapcs" |
+            "win64" |
+            "sysv64" |
+            "system" => {}
+            "rust-intrinsic" => {
                 gate_feature_post!(&self, intrinsics, span,
                                    "intrinsics are subject to change");
             },
-            Abi::PlatformIntrinsic => {
+            "platform-intrinsic" => {
                 gate_feature_post!(&self, platform_intrinsics, span,
                                    "platform intrinsics are experimental and possibly buggy");
             },
-            Abi::Vectorcall => {
+            "vectorcall" => {
                 gate_feature_post!(&self, abi_vectorcall, span,
                                    "vectorcall is experimental and subject to change");
             },
-            Abi::Thiscall => {
+            "thiscall" => {
                 gate_feature_post!(&self, abi_thiscall, span,
                                    "thiscall is experimental and subject to change");
             },
-            Abi::RustCall => {
+            "rust-call" => {
                 gate_feature_post!(&self, unboxed_closures, span,
                                    "rust-call ABI is subject to change");
             },
-            Abi::PtxKernel => {
+            "ptx-kernel" => {
                 gate_feature_post!(&self, abi_ptx, span,
                                    "PTX ABIs are experimental and subject to change");
             },
-            Abi::Unadjusted => {
+            "unadjusted" => {
                 gate_feature_post!(&self, abi_unadjusted, span,
                                    "unadjusted ABI is an implementation detail and perma-unstable");
             },
-            Abi::Msp430Interrupt => {
+            "msp430-interrupt" => {
                 gate_feature_post!(&self, abi_msp430_interrupt, span,
                                    "msp430-interrupt ABI is experimental and subject to change");
             },
-            Abi::X86Interrupt => {
+            "x86-interrupt" => {
                 gate_feature_post!(&self, abi_x86_interrupt, span,
                                    "x86-interrupt ABI is experimental and subject to change");
             },
-            Abi::AmdGpuKernel => {
+            "amdgpu-kernel" => {
                 gate_feature_post!(&self, abi_amdgpu_kernel, span,
                                    "amdgpu-kernel ABI is experimental and subject to change");
             },
-            Abi::EfiApi => {
+            "efiapi" => {
                 gate_feature_post!(&self, abi_efiapi, span,
                                    "efiapi ABI is experimental and subject to change");
             },
-            // Stable
-            Abi::Cdecl |
-            Abi::Stdcall |
-            Abi::Fastcall |
-            Abi::Aapcs |
-            Abi::Win64 |
-            Abi::SysV64 |
-            Abi::Rust |
-            Abi::C |
-            Abi::System => {}
+            abi => {
+                self.parse_sess.span_diagnostic.delay_span_bug(
+                    span,
+                    &format!("unrecognized ABI not caught in lowering: {}", abi),
+                )
+            }
         }
     }
 
@@ -373,7 +380,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_item(&mut self, i: &'a ast::Item) {
         match i.kind {
             ast::ItemKind::ForeignMod(ref foreign_module) => {
-                self.check_abi(foreign_module.abi, i.span);
+                self.check_abi(foreign_module.abi);
             }
 
             ast::ItemKind::Fn(..) => {
@@ -503,7 +510,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_ty(&mut self, ty: &'a ast::Ty) {
         match ty.kind {
             ast::TyKind::BareFn(ref bare_fn_ty) => {
-                self.check_abi(bare_fn_ty.abi, ty.span);
+                self.check_abi(bare_fn_ty.abi);
             }
             ast::TyKind::Never => {
                 gate_feature_post!(&self, never_type, ty.span,
@@ -597,7 +604,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             // Stability of const fn methods are covered in
             // `visit_trait_item` and `visit_impl_item` below; this is
             // because default methods don't pass through this point.
-            self.check_abi(header.abi, span);
+            self.check_abi(header.abi);
         }
 
         if fn_decl.c_variadic() {
@@ -631,7 +638,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         match ti.kind {
             ast::TraitItemKind::Method(ref sig, ref block) => {
                 if block.is_none() {
-                    self.check_abi(sig.header.abi, ti.span);
+                    self.check_abi(sig.header.abi);
                 }
                 if sig.decl.c_variadic() {
                     gate_feature_post!(&self, c_variadic, ti.span,
@@ -863,18 +870,17 @@ pub fn check_crate(krate: &ast::Crate,
     maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
     let mut visitor = PostExpansionVisitor { parse_sess, features };
 
+    let spans = parse_sess.gated_spans.spans.borrow();
     macro_rules! gate_all {
-        ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); };
-        ($spans:ident, $gate:ident, $msg:literal) => {
-            for span in &*parse_sess.gated_spans.$spans.borrow() {
+        ($gate:ident, $msg:literal) => {
+            for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
                 gate_feature!(&visitor, $gate, *span, $msg);
             }
         }
     }
-
     gate_all!(let_chains, "`let` expressions in this position are experimental");
     gate_all!(async_closure, "async closures are unstable");
-    gate_all!(yields, generators, "yield syntax is experimental");
+    gate_all!(generators, "yield syntax is experimental");
     gate_all!(or_patterns, "or-patterns syntax is experimental");
     gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
 
@@ -885,7 +891,7 @@ pub fn check_crate(krate: &ast::Crate,
             // FIXME(eddyb) do something more useful than always
             // disabling these uses of early feature-gatings.
             if false {
-                for span in &*parse_sess.gated_spans.$gate.borrow() {
+                for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
                     gate_feature!(&visitor, $gate, *span, $msg);
                 }
             }
@@ -902,7 +908,6 @@ pub fn check_crate(krate: &ast::Crate,
     gate_all!(try_blocks, "`try` blocks are unstable");
     gate_all!(label_break_value, "labels on blocks are unstable");
     gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
-
     // To avoid noise about type ascription in common syntax errors,
     // only emit if it is the *only* error. (Also check it last.)
     if parse_sess.span_diagnostic.err_count() == 0 {
diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs
index c42f4aa25cc..a8eeac59954 100644
--- a/src/libsyntax/parse/literal.rs
+++ b/src/libsyntax/parse/literal.rs
@@ -157,17 +157,18 @@ impl LitKind {
             }
             LitKind::Int(n, ty) => {
                 let suffix = match ty {
-                    ast::LitIntType::Unsigned(ty) => Some(ty.to_symbol()),
-                    ast::LitIntType::Signed(ty) => Some(ty.to_symbol()),
+                    ast::LitIntType::Unsigned(ty) => Some(ty.name()),
+                    ast::LitIntType::Signed(ty) => Some(ty.name()),
                     ast::LitIntType::Unsuffixed => None,
                 };
                 (token::Integer, sym::integer(n), suffix)
             }
             LitKind::Float(symbol, ty) => {
-                (token::Float, symbol, Some(ty.to_symbol()))
-            }
-            LitKind::FloatUnsuffixed(symbol) => {
-                (token::Float, symbol, None)
+                let suffix = match ty {
+                    ast::LitFloatType::Suffixed(ty) => Some(ty.name()),
+                    ast::LitFloatType::Unsuffixed => None,
+                };
+                (token::Float, symbol, suffix)
             }
             LitKind::Bool(value) => {
                 let symbol = if value { kw::True } else { kw::False };
@@ -244,12 +245,12 @@ fn filtered_float_lit(symbol: Symbol, suffix: Option<Symbol>, base: u32)
         return Err(LitError::NonDecimalFloat(base));
     }
     Ok(match suffix {
-        Some(suf) => match suf {
-            sym::f32 => LitKind::Float(symbol, ast::FloatTy::F32),
-            sym::f64 => LitKind::Float(symbol, ast::FloatTy::F64),
+        Some(suf) => LitKind::Float(symbol, ast::LitFloatType::Suffixed(match suf {
+            sym::f32 => ast::FloatTy::F32,
+            sym::f64 => ast::FloatTy::F64,
             _ => return Err(LitError::InvalidFloatSuffix),
-        }
-        None => LitKind::FloatUnsuffixed(symbol)
+        })),
+        None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed)
     })
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 7652c730e51..1284e89f195 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -12,7 +12,7 @@ mod diagnostics;
 use diagnostics::Error;
 
 use crate::ast::{
-    self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
+    self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
     IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
 };
 use crate::parse::{PResult, Directory, DirectoryOwnership};
@@ -28,7 +28,6 @@ use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
 use crate::ThinVec;
 
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
-use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{Span, BytePos, DUMMY_SP, FileName};
 use log::debug;
 
@@ -1121,7 +1120,7 @@ impl<'a> Parser<'a> {
         self.expected_tokens.push(TokenType::Keyword(kw::Crate));
         if self.is_crate_vis() {
             self.bump(); // `crate`
-            self.sess.gated_spans.crate_visibility_modifier.borrow_mut().push(self.prev_span);
+            self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_span);
             return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate)));
         }
 
@@ -1206,48 +1205,41 @@ impl<'a> Parser<'a> {
         Ok(())
     }
 
-    /// Parses `extern` followed by an optional ABI string, or nothing.
+    /// Parses `extern string_literal?`.
+    /// If `extern` is not found, the Rust ABI is used.
+    /// If `extern` is found and a `string_literal` does not follow, the C ABI is used.
     fn parse_extern_abi(&mut self) -> PResult<'a, Abi> {
-        if self.eat_keyword(kw::Extern) {
-            Ok(self.parse_opt_abi()?.unwrap_or(Abi::C))
+        Ok(if self.eat_keyword(kw::Extern) {
+            self.parse_opt_abi()?
         } else {
-            Ok(Abi::Rust)
-        }
+            Abi::default()
+        })
     }
 
-    /// Parses a string as an ABI spec on an extern type or module. Consumes
-    /// the `extern` keyword, if one is found.
-    fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
-        match self.token.kind {
-            token::Literal(token::Lit { kind: token::Str, symbol, suffix }) |
-            token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => {
-                self.expect_no_suffix(self.token.span, "an ABI spec", suffix);
-                self.bump();
-                match abi::lookup(&symbol.as_str()) {
-                    Some(abi) => Ok(Some(abi)),
-                    None => {
-                        self.error_on_invalid_abi(symbol);
-                        Ok(None)
-                    }
+    /// Parses a string literal as an ABI spec.
+    /// If one is not found, the "C" ABI is used.
+    fn parse_opt_abi(&mut self) -> PResult<'a, Abi> {
+        let span = if self.token.can_begin_literal_or_bool() {
+            let ast::Lit { span, kind, .. } = self.parse_lit()?;
+            match kind {
+                ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)),
+                ast::LitKind::Err(_) => {}
+                _ => {
+                    self.struct_span_err(span, "non-string ABI literal")
+                        .span_suggestion(
+                            span,
+                            "specify the ABI with a string literal",
+                            "\"C\"".to_string(),
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
                 }
             }
-            _ => Ok(None),
-        }
-    }
-
-    /// Emit an error where `symbol` is an invalid ABI.
-    fn error_on_invalid_abi(&self, symbol: Symbol) {
-        let prev_span = self.prev_span;
-        struct_span_err!(
-            self.sess.span_diagnostic,
-            prev_span,
-            E0703,
-            "invalid ABI: found `{}`",
-            symbol
-        )
-        .span_label(prev_span, "invalid ABI")
-        .help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
-        .emit();
+            span
+        } else {
+            self.prev_span
+        };
+        Ok(Abi::new(sym::C, span))
     }
 
     /// We are parsing `async fn`. If we are on Rust 2015, emit an error.
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index 97b1092452a..509e6482dcc 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -16,10 +16,10 @@ use crate::parse::token::{self, Token, TokenKind};
 use crate::print::pprust;
 use crate::ptr::P;
 use crate::source_map::{self, Span};
-use crate::symbol::{kw, sym};
 use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
 
 use errors::Applicability;
+use syntax_pos::symbol::{kw, sym};
 use syntax_pos::Symbol;
 use std::mem;
 use rustc_data_structures::thin_vec::ThinVec;
@@ -252,7 +252,7 @@ impl<'a> Parser<'a> {
                 self.last_type_ascription = Some((self.prev_span, maybe_path));
 
                 lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
-                self.sess.gated_spans.type_ascription.borrow_mut().push(lhs.span);
+                self.sess.gated_spans.gate(sym::type_ascription, lhs.span);
                 continue
             } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
                 // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to
@@ -455,7 +455,7 @@ impl<'a> Parser<'a> {
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
                 let span = lo.to(span);
-                self.sess.gated_spans.box_syntax.borrow_mut().push(span);
+                self.sess.gated_spans.gate(sym::box_syntax, span);
                 (span, ExprKind::Box(e))
             }
             token::Ident(..) if self.token.is_ident_named(sym::not) => {
@@ -1045,7 +1045,7 @@ impl<'a> Parser<'a> {
                     }
 
                     let span = lo.to(hi);
-                    self.sess.gated_spans.yields.borrow_mut().push(span);
+                    self.sess.gated_spans.gate(sym::generators, span);
                 } else if self.eat_keyword(kw::Let) {
                     return self.parse_let_expr(attrs);
                 } else if is_span_rust_2018 && self.eat_keyword(kw::Await) {
@@ -1116,7 +1116,11 @@ impl<'a> Parser<'a> {
                 Err(self.span_fatal(token.span, &msg))
             }
             Err(err) => {
-                let (lit, span) = (token.expect_lit(), token.span);
+                let span = token.span;
+                let lit = match token.kind {
+                    token::Literal(lit) => lit,
+                    _ => unreachable!(),
+                };
                 self.bump();
                 self.error_literal_from_token(err, lit, span);
                 // Pack possible quotes and prefixes from the original literal into
@@ -1264,7 +1268,7 @@ impl<'a> Parser<'a> {
         outer_attrs: ThinVec<Attribute>,
     ) -> PResult<'a, P<Expr>> {
         if let Some(label) = opt_label {
-            self.sess.gated_spans.label_break_value.borrow_mut().push(label.ident.span);
+            self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
         }
 
         self.expect(&token::OpenDelim(token::Brace))?;
@@ -1293,7 +1297,7 @@ impl<'a> Parser<'a> {
         };
         if asyncness.is_async() {
             // Feature-gate `async ||` closures.
-            self.sess.gated_spans.async_closure.borrow_mut().push(self.prev_span);
+            self.sess.gated_spans.gate(sym::async_closure, self.prev_span);
         }
 
         let capture_clause = self.parse_capture_clause();
@@ -1415,8 +1419,7 @@ impl<'a> Parser<'a> {
 
         if let ExprKind::Let(..) = cond.kind {
             // Remove the last feature gating of a `let` expression since it's stable.
-            let last = self.sess.gated_spans.let_chains.borrow_mut().pop();
-            debug_assert_eq!(cond.span, last.unwrap());
+            self.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
         }
 
         Ok(cond)
@@ -1433,7 +1436,7 @@ impl<'a> Parser<'a> {
             |this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
         )?;
         let span = lo.to(expr.span);
-        self.sess.gated_spans.let_chains.borrow_mut().push(span);
+        self.sess.gated_spans.gate(sym::let_chains, span);
         Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs))
     }
 
@@ -1654,7 +1657,7 @@ impl<'a> Parser<'a> {
             Err(error)
         } else {
             let span = span_lo.to(body.span);
-            self.sess.gated_spans.try_blocks.borrow_mut().push(span);
+            self.sess.gated_spans.gate(sym::try_blocks, span);
             Ok(self.mk_expr(span, ExprKind::TryBlock(body), attrs))
         }
     }
diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs
index 51caae69c86..3c094750b4d 100644
--- a/src/libsyntax/parse/parser/generics.rs
+++ b/src/libsyntax/parse/parser/generics.rs
@@ -3,7 +3,8 @@ use super::{Parser, PResult};
 use crate::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute};
 use crate::parse::token;
 use crate::source_map::DUMMY_SP;
-use crate::symbol::kw;
+
+use syntax_pos::symbol::{kw, sym};
 
 impl<'a> Parser<'a> {
     /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
@@ -62,7 +63,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
-        self.sess.gated_spans.const_generics.borrow_mut().push(lo.to(self.prev_span));
+        self.sess.gated_spans.gate(sym::const_generics, lo.to(self.prev_span));
 
         Ok(GenericParam {
             ident,
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index cc6235c6fc7..9d543055f23 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -3,7 +3,7 @@ use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim};
 
 use crate::maybe_whole;
 use crate::ptr::P;
-use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
+use crate::ast::{self, Abi, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
 use crate::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
 use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness};
 use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
@@ -17,7 +17,6 @@ use crate::ThinVec;
 
 use log::debug;
 use std::mem;
-use rustc_target::spec::abi::Abi;
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
 use syntax_pos::BytePos;
 
@@ -111,7 +110,7 @@ impl<'a> Parser<'a> {
                 return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
             }
 
-            let opt_abi = self.parse_opt_abi()?;
+            let abi = self.parse_opt_abi()?;
 
             if self.eat_keyword(kw::Fn) {
                 // EXTERN FUNCTION ITEM
@@ -120,12 +119,12 @@ impl<'a> Parser<'a> {
                     unsafety: Unsafety::Normal,
                     asyncness: respan(fn_span, IsAsync::NotAsync),
                     constness: respan(fn_span, Constness::NotConst),
-                    abi: opt_abi.unwrap_or(Abi::C),
+                    abi,
                 };
                 return self.parse_item_fn(lo, vis, attrs, header);
             } else if self.check(&token::OpenDelim(token::Brace)) {
                 return Ok(Some(
-                    self.parse_item_foreign_mod(lo, opt_abi, vis, attrs, extern_sp)?,
+                    self.parse_item_foreign_mod(lo, abi, vis, attrs, extern_sp)?,
                 ));
             }
 
@@ -147,9 +146,7 @@ impl<'a> Parser<'a> {
                 let unsafety = self.parse_unsafety();
 
                 if self.check_keyword(kw::Extern) {
-                    self.sess.gated_spans.const_extern_fn.borrow_mut().push(
-                        lo.to(self.token.span)
-                    );
+                    self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span));
                 }
                 let abi = self.parse_extern_abi()?;
                 self.bump(); // `fn`
@@ -201,7 +198,7 @@ impl<'a> Parser<'a> {
                     unsafety,
                     asyncness,
                     constness: respan(fn_span, Constness::NotConst),
-                    abi: Abi::Rust,
+                    abi: Abi::new(sym::Rust, fn_span),
                 };
                 return self.parse_item_fn(lo, vis, attrs, header);
             }
@@ -238,7 +235,7 @@ impl<'a> Parser<'a> {
                 unsafety: Unsafety::Normal,
                 asyncness: respan(fn_span, IsAsync::NotAsync),
                 constness: respan(fn_span, Constness::NotConst),
-                abi: Abi::Rust,
+                abi: Abi::new(sym::Rust, fn_span),
             };
             return self.parse_item_fn(lo, vis, attrs, header);
         }
@@ -832,7 +829,7 @@ impl<'a> Parser<'a> {
                     .emit();
             }
 
-            self.sess.gated_spans.trait_alias.borrow_mut().push(whole_span);
+            self.sess.gated_spans.gate(sym::trait_alias, whole_span);
 
             Ok((ident, ItemKind::TraitAlias(tps, bounds), None))
         } else {
@@ -1115,15 +1112,13 @@ impl<'a> Parser<'a> {
     fn parse_item_foreign_mod(
         &mut self,
         lo: Span,
-        opt_abi: Option<Abi>,
+        abi: Abi,
         visibility: Visibility,
         mut attrs: Vec<Attribute>,
         extern_sp: Span,
     ) -> PResult<'a, P<Item>> {
         self.expect(&token::OpenDelim(token::Brace))?;
 
-        let abi = opt_abi.unwrap_or(Abi::C);
-
         attrs.extend(self.parse_inner_attributes()?);
 
         let mut foreign_items = vec![];
@@ -1714,7 +1709,7 @@ impl<'a> Parser<'a> {
         let span = lo.to(self.prev_span);
 
         if !def.legacy {
-            self.sess.gated_spans.decl_macro.borrow_mut().push(span);
+            self.sess.gated_spans.gate(sym::decl_macro, span);
         }
 
         Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec())))
@@ -1801,7 +1796,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, Option<P<Item>>> {
         let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
             is_self_allowed: false,
-            allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe,
+            allow_c_variadic: header.abi.symbol == sym::C && header.unsafety == Unsafety::Unsafe,
             is_name_required: |_| true,
         })?;
         let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1930,7 +1925,7 @@ impl<'a> Parser<'a> {
         let asyncness = respan(self.prev_span, asyncness);
         let unsafety = self.parse_unsafety();
         let (constness, unsafety, abi) = if is_const_fn {
-            (respan(const_span, Constness::Const), unsafety, Abi::Rust)
+            (respan(const_span, Constness::Const), unsafety, Abi::default())
         } else {
             let abi = self.parse_extern_abi()?;
             (respan(self.prev_span, Constness::NotConst), unsafety, abi)
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index 969d5dd8374..cc8738edff7 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -8,9 +8,8 @@ use crate::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor};
 use crate::parse::token::{self};
 use crate::print::pprust;
 use crate::source_map::{respan, Span, Spanned};
-use crate::symbol::kw;
 use crate::ThinVec;
-
+use syntax_pos::symbol::{kw, sym};
 use errors::{Applicability, DiagnosticBuilder};
 
 type Expected = Option<&'static str>;
@@ -52,11 +51,8 @@ impl<'a> Parser<'a> {
         // and no other gated or-pattern has been parsed thus far,
         // then we should really gate the leading `|`.
         // This complicated procedure is done purely for diagnostics UX.
-        if gated_leading_vert {
-            let mut or_pattern_spans = self.sess.gated_spans.or_patterns.borrow_mut();
-            if or_pattern_spans.is_empty() {
-                or_pattern_spans.push(leading_vert_span);
-            }
+        if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) {
+            self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span);
         }
 
         Ok(pat)
@@ -117,7 +113,7 @@ impl<'a> Parser<'a> {
 
         // Feature gate the or-pattern if instructed:
         if gate_or == GateOr::Yes {
-            self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span);
+            self.sess.gated_spans.gate(sym::or_patterns, or_pattern_span);
         }
 
         Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
@@ -325,7 +321,7 @@ impl<'a> Parser<'a> {
             } else if self.eat_keyword(kw::Box) {
                 // Parse `box pat`
                 let pat = self.parse_pat_with_range_pat(false, None)?;
-                self.sess.gated_spans.box_patterns.borrow_mut().push(lo.to(self.prev_span));
+                self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_span));
                 PatKind::Box(pat)
             } else if self.can_be_ident_pat() {
                 // Parse `ident @ pat`
@@ -612,7 +608,7 @@ impl<'a> Parser<'a> {
     }
 
     fn excluded_range_end(&self, span: Span) -> RangeEnd {
-        self.sess.gated_spans.exclusive_range_pattern.borrow_mut().push(span);
+        self.sess.gated_spans.gate(sym::exclusive_range_pattern, span);
         RangeEnd::Excluded
     }
 
diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs
index f9944e36e2f..4438d61d9ee 100644
--- a/src/libsyntax/parse/parser/path.rs
+++ b/src/libsyntax/parse/parser/path.rs
@@ -5,7 +5,7 @@ use crate::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, Angle
 use crate::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
 use crate::parse::token::{self, Token};
 use crate::source_map::{Span, BytePos};
-use crate::symbol::kw;
+use syntax_pos::symbol::{kw, sym};
 
 use std::mem;
 use log::debug;
@@ -426,7 +426,7 @@ impl<'a> Parser<'a> {
 
                 // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
                 if let AssocTyConstraintKind::Bound { .. } = kind {
-                    self.sess.gated_spans.associated_type_bounds.borrow_mut().push(span);
+                    self.sess.gated_spans.gate(sym::associated_type_bounds, span);
                 }
 
                 constraints.push(AssocTyConstraint {
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 03e77b199cc..6f3da344ccf 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -381,9 +381,7 @@ impl Token {
         match self.kind {
             OpenDelim(Brace) => true,
             Interpolated(ref nt) => match **nt {
-                NtExpr(..) => true,
-                NtBlock(..) => true,
-                NtLiteral(..) => true,
+                NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
                 _ => false,
             }
             _ => self.can_begin_literal_or_bool(),
@@ -404,13 +402,6 @@ impl Token {
         }
     }
 
-    crate fn expect_lit(&self) -> Lit {
-        match self.kind {
-            Literal(lit) => lit,
-            _ => panic!("`expect_lit` called on non-literal"),
-        }
-    }
-
     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
     /// for example a '-42', or one of the boolean idents).
     pub fn can_begin_literal_or_bool(&self) -> bool {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c8afe8a1ff4..1d59c13a9d0 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -14,7 +14,6 @@ use crate::sess::ParseSess;
 use crate::symbol::{kw, sym};
 use crate::tokenstream::{self, TokenStream, TokenTree};
 
-use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{self, BytePos};
 use syntax_pos::{FileName, Span};
 
@@ -1230,7 +1229,7 @@ impl<'a> State<'a> {
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
                 self.head("extern");
-                self.word_nbsp(nmod.abi.to_string());
+                self.print_abi(nmod.abi);
                 self.bopen();
                 self.print_foreign_mod(nmod, &item.attrs);
                 self.bclose(item.span);
@@ -2823,7 +2822,7 @@ impl<'a> State<'a> {
     }
 
     crate fn print_ty_fn(&mut self,
-                       abi: abi::Abi,
+                       abi: ast::Abi,
                        unsafety: ast::Unsafety,
                        decl: &ast::FnDecl,
                        name: Option<ast::Ident>,
@@ -2884,14 +2883,18 @@ impl<'a> State<'a> {
         self.print_asyncness(header.asyncness.node);
         self.print_unsafety(header.unsafety);
 
-        if header.abi != Abi::Rust {
+        if header.abi.symbol != sym::Rust {
             self.word_nbsp("extern");
-            self.word_nbsp(header.abi.to_string());
+            self.print_abi(header.abi);
         }
 
         self.s.word("fn")
     }
 
+    fn print_abi(&mut self, abi: ast::Abi) {
+        self.word_nbsp(format!("\"{}\"", abi.symbol));
+    }
+
     crate fn print_unsafety(&mut self, s: ast::Unsafety) {
         match s {
             ast::Unsafety::Normal => {},
diff --git a/src/libsyntax/print/pprust/tests.rs b/src/libsyntax/print/pprust/tests.rs
index faa70edbfa2..2c6dd0fb1c6 100644
--- a/src/libsyntax/print/pprust/tests.rs
+++ b/src/libsyntax/print/pprust/tests.rs
@@ -34,12 +34,7 @@ fn test_fun_to_string() {
         assert_eq!(
             fun_to_string(
                 &decl,
-                ast::FnHeader {
-                    unsafety: ast::Unsafety::Normal,
-                    constness: source_map::dummy_spanned(ast::Constness::NotConst),
-                    asyncness: source_map::dummy_spanned(ast::IsAsync::NotAsync),
-                    abi: Abi::Rust,
-                },
+                ast::FnHeader::default(),
                 abba_ident,
                 &generics
             ),
diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs
index 30f8c56a056..faad3e4af1e 100644
--- a/src/libsyntax/sess.rs
+++ b/src/libsyntax/sess.rs
@@ -19,39 +19,53 @@ use std::str;
 /// Collected spans during parsing for places where a certain feature was
 /// used and should be feature gated accordingly in `check_crate`.
 #[derive(Default)]
-crate struct GatedSpans {
-    /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`.
-    crate let_chains: Lock<Vec<Span>>,
-    /// Spans collected for gating `async_closure`, e.g. `async || ..`.
-    crate async_closure: Lock<Vec<Span>>,
-    /// Spans collected for gating `yield e?` expressions (`generators` gate).
-    crate yields: Lock<Vec<Span>>,
-    /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`.
-    crate or_patterns: Lock<Vec<Span>>,
-    /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`.
-    crate const_extern_fn: Lock<Vec<Span>>,
-    /// Spans collected for gating `trait_alias`, e.g. `trait Foo = Ord + Eq;`.
-    pub trait_alias: Lock<Vec<Span>>,
-    /// Spans collected for gating `associated_type_bounds`, e.g. `Iterator<Item: Ord>`.
-    pub associated_type_bounds: Lock<Vec<Span>>,
-    /// Spans collected for gating `crate_visibility_modifier`, e.g. `crate fn`.
-    pub crate_visibility_modifier: Lock<Vec<Span>>,
-    /// Spans collected for gating `const_generics`, e.g. `const N: usize`.
-    pub const_generics: Lock<Vec<Span>>,
-    /// Spans collected for gating `decl_macro`, e.g. `macro m() {}`.
-    pub decl_macro: Lock<Vec<Span>>,
-    /// Spans collected for gating `box_patterns`, e.g. `box 0`.
-    pub box_patterns: Lock<Vec<Span>>,
-    /// Spans collected for gating `exclusive_range_pattern`, e.g. `0..2`.
-    pub exclusive_range_pattern: Lock<Vec<Span>>,
-    /// Spans collected for gating `try_blocks`, e.g. `try { a? + b? }`.
-    pub try_blocks: Lock<Vec<Span>>,
-    /// Spans collected for gating `label_break_value`, e.g. `'label: { ... }`.
-    pub label_break_value: Lock<Vec<Span>>,
-    /// Spans collected for gating `box_syntax`, e.g. `box $expr`.
-    pub box_syntax: Lock<Vec<Span>>,
-    /// Spans collected for gating `type_ascription`, e.g. `42: usize`.
-    pub type_ascription: Lock<Vec<Span>>,
+pub struct GatedSpans {
+    pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
+}
+
+impl GatedSpans {
+    /// Feature gate the given `span` under the given `feature`
+    /// which is same `Symbol` used in `active.rs`.
+    pub fn gate(&self, feature: Symbol, span: Span) {
+        self.spans
+            .borrow_mut()
+            .entry(feature)
+            .or_default()
+            .push(span);
+    }
+
+    /// Ungate the last span under the given `feature`.
+    /// Panics if the given `span` wasn't the last one.
+    ///
+    /// Using this is discouraged unless you have a really good reason to.
+    pub fn ungate_last(&self, feature: Symbol, span: Span) {
+        let removed_span = self.spans
+            .borrow_mut()
+            .entry(feature)
+            .or_default()
+            .pop()
+            .unwrap();
+        debug_assert_eq!(span, removed_span);
+    }
+
+    /// Is the provided `feature` gate ungated currently?
+    ///
+    /// Using this is discouraged unless you have a really good reason to.
+    pub fn is_ungated(&self, feature: Symbol) -> bool {
+        self.spans
+            .borrow()
+            .get(&feature)
+            .map_or(true, |spans| spans.is_empty())
+    }
+
+    /// Prepend the given set of `spans` onto the set in `self`.
+    pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
+        let mut inner = self.spans.borrow_mut();
+        for (gate, mut gate_spans) in inner.drain() {
+            spans.entry(gate).or_default().append(&mut gate_spans);
+        }
+        *inner = spans;
+    }
 }
 
 /// Info about a parsing session.
@@ -72,7 +86,7 @@ pub struct ParseSess {
     /// analysis.
     pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
     pub injected_crate_name: Once<Symbol>,
-    crate gated_spans: GatedSpans,
+    pub gated_spans: GatedSpans,
     /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
     pub reached_eof: Lock<bool>,
 }
diff --git a/src/libsyntax_expand/Cargo.toml b/src/libsyntax_expand/Cargo.toml
index d98b9457a62..02c711bc387 100644
--- a/src/libsyntax_expand/Cargo.toml
+++ b/src/libsyntax_expand/Cargo.toml
@@ -21,6 +21,5 @@ errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_index = { path = "../librustc_index" }
 rustc_lexer = { path = "../librustc_lexer" }
-rustc_target = { path = "../librustc_target" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs
index 7a772b0d31d..55719907403 100644
--- a/src/libsyntax_expand/mbe/macro_rules.rs
+++ b/src/libsyntax_expand/mbe/macro_rules.rs
@@ -29,7 +29,7 @@ use syntax_pos::Span;
 use rustc_data_structures::fx::FxHashMap;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
-use std::slice;
+use std::{mem, slice};
 
 use errors::Applicability;
 use rustc_data_structures::sync::Lrc;
@@ -182,7 +182,6 @@ fn generic_extension<'cx>(
 
     // Which arm's failure should we report? (the one furthest along)
     let mut best_failure: Option<(Token, &str)> = None;
-
     for (i, lhs) in lhses.iter().enumerate() {
         // try each arm's matchers
         let lhs_tt = match *lhs {
@@ -190,8 +189,18 @@ fn generic_extension<'cx>(
             _ => cx.span_bug(sp, "malformed macro lhs"),
         };
 
+        // Take a snapshot of the state of pre-expansion gating at this point.
+        // This is used so that if a matcher is not `Success(..)`ful,
+        // then the spans which became gated when parsing the unsucessful matcher
+        // are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
+        let mut gated_spans_snaphot = mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut());
+
         match parse_tt(cx, lhs_tt, arg.clone()) {
             Success(named_matches) => {
+                // The matcher was `Success(..)`ful.
+                // Merge the gated spans from parsing the matcher with the pre-existing ones.
+                cx.parse_sess.gated_spans.merge(gated_spans_snaphot);
+
                 let rhs = match rhses[i] {
                     // ignore delimiters
                     mbe::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
@@ -248,6 +257,10 @@ fn generic_extension<'cx>(
             },
             Error(err_sp, ref msg) => cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]),
         }
+
+        // The matcher was not `Success(..)`ful.
+        // Restore to the state before snapshotting and maybe try again.
+        mem::swap(&mut gated_spans_snaphot, &mut cx.parse_sess.gated_spans.spans.borrow_mut());
     }
 
     let (token, label) = best_failure.expect("ran no matchers");
diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs
index 47bade698a8..4bf13f37711 100644
--- a/src/libsyntax_ext/concat.rs
+++ b/src/libsyntax_ext/concat.rs
@@ -21,8 +21,7 @@ pub fn expand_concat(
         match e.kind {
             ast::ExprKind::Lit(ref lit) => match lit.kind {
                 ast::LitKind::Str(ref s, _)
-                | ast::LitKind::Float(ref s, _)
-                | ast::LitKind::FloatUnsuffixed(ref s) => {
+                | ast::LitKind::Float(ref s, _) => {
                     accumulator.push_str(&s.as_str());
                 }
                 ast::LitKind::Char(c) => {
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 2e5ae235893..b18fd50ae76 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -182,8 +182,7 @@ use std::iter;
 use std::vec;
 
 use rustc_data_structures::thin_vec::ThinVec;
-use rustc_target::spec::abi::Abi;
-use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind};
+use syntax::ast::{self, Abi, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind};
 use syntax::ast::{VariantData, GenericParamKind, GenericArg};
 use syntax::attr;
 use syntax::source_map::respan;
@@ -738,7 +737,7 @@ impl<'a> TraitDef<'a> {
                                          self,
                                          type_ident,
                                          generics,
-                                         Abi::Rust,
+                                         sym::Rust,
                                          explicit_self,
                                          tys,
                                          body)
@@ -793,7 +792,7 @@ impl<'a> TraitDef<'a> {
                                          self,
                                          type_ident,
                                          generics,
-                                         Abi::Rust,
+                                         sym::Rust,
                                          explicit_self,
                                          tys,
                                          body)
@@ -919,7 +918,7 @@ impl<'a> MethodDef<'a> {
                      trait_: &TraitDef<'_>,
                      type_ident: Ident,
                      generics: &Generics,
-                     abi: Abi,
+                     abi: Symbol,
                      explicit_self: Option<ast::ExplicitSelf>,
                      arg_types: Vec<(Ident, P<ast::Ty>)>,
                      body: P<Expr>)
@@ -949,23 +948,27 @@ impl<'a> MethodDef<'a> {
             ast::Unsafety::Normal
         };
 
+        let trait_lo_sp = trait_.span.shrink_to_lo();
+
+        let sig = ast::MethodSig {
+            header: ast::FnHeader {
+                unsafety,
+                abi: Abi::new(abi, trait_lo_sp),
+                ..ast::FnHeader::default()
+            },
+            decl: fn_decl,
+        };
+
         // Create the method.
         ast::ImplItem {
             id: ast::DUMMY_NODE_ID,
             attrs: self.attributes.clone(),
             generics: fn_generics,
             span: trait_.span,
-            vis: respan(trait_.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
+            vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited),
             defaultness: ast::Defaultness::Final,
             ident: method_ident,
-            kind: ast::ImplItemKind::Method(ast::MethodSig {
-                                                header: ast::FnHeader {
-                                                    unsafety, abi,
-                                                    ..ast::FnHeader::default()
-                                                },
-                                                decl: fn_decl,
-                                            },
-                                            body_block),
+            kind: ast::ImplItemKind::Method(sig, body_block),
             tokens: None,
         }
     }
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 64ea82e1bdc..d87b17eee31 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -566,6 +566,7 @@ symbols! {
         rust_2018_preview,
         rust_begin_unwind,
         rustc,
+        Rust,
         RustcDecodable,
         RustcEncodable,
         rustc_allocator,
diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs
index 9de774555e9..e0e211444cf 100644
--- a/src/libtest/tests.rs
+++ b/src/libtest/tests.rs
@@ -269,7 +269,7 @@ fn time_test_failure_template(test_type: TestType) -> TestResult {
 fn test_error_on_exceed() {
     let types = [TestType::UnitTest, TestType::IntegrationTest, TestType::DocTest];
 
-    for test_type in types.into_iter() {
+    for test_type in types.iter() {
         let result = time_test_failure_template(*test_type);
 
         assert_eq!(result, TestResult::TrTimedFail);
@@ -320,7 +320,7 @@ fn test_time_options_threshold() {
         (TestType::DocTest, doc.critical.as_millis(), true, true),
     ];
 
-    for (test_type, time, expected_warn, expected_critical) in test_vector.into_iter() {
+    for (test_type, time, expected_warn, expected_critical) in test_vector.iter() {
         let test_desc = typed_test_desc(*test_type);
         let exec_time = test_exec_time(*time as u64);
 
diff --git a/src/test/ui/feature-gated-feature-in-macro-arg.stderr b/src/test/ui/feature-gated-feature-in-macro-arg.stderr
index 5ee05154c3a..218e0292776 100644
--- a/src/test/ui/feature-gated-feature-in-macro-arg.stderr
+++ b/src/test/ui/feature-gated-feature-in-macro-arg.stderr
@@ -1,10 +1,8 @@
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gated-feature-in-macro-arg.rs:8:9
+  --> $DIR/feature-gated-feature-in-macro-arg.rs:8:16
    |
-LL | /         extern "rust-intrinsic" {
-LL | |             fn atomic_fence();
-LL | |         }
-   | |_________^
+LL |         extern "rust-intrinsic" {
+   |                ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr
index 0d2e355535d..d58a2d91b2b 100644
--- a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr
@@ -1,8 +1,8 @@
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi-msp430-interrupt.rs:4:1
+  --> $DIR/feature-gate-abi-msp430-interrupt.rs:4:8
    |
 LL | extern "msp430-interrupt" fn foo() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr
index 0f2622f1065..6db6cb49cef 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi.stderr
@@ -1,591 +1,591 @@
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:13:1
+  --> $DIR/feature-gate-abi.rs:13:8
    |
 LL | extern "rust-intrinsic" fn f1() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:15:1
+  --> $DIR/feature-gate-abi.rs:15:8
    |
 LL | extern "platform-intrinsic" fn f2() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/27731
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:17:1
+  --> $DIR/feature-gate-abi.rs:17:8
    |
 LL | extern "vectorcall" fn f3() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:18:1
+  --> $DIR/feature-gate-abi.rs:18:8
    |
 LL | extern "rust-call" fn f4() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:19:1
+  --> $DIR/feature-gate-abi.rs:19:8
    |
 LL | extern "msp430-interrupt" fn f5() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:20:1
+  --> $DIR/feature-gate-abi.rs:20:8
    |
 LL | extern "ptx-kernel" fn f6() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38788
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:21:1
+  --> $DIR/feature-gate-abi.rs:21:8
    |
 LL | extern "x86-interrupt" fn f7() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/40180
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:22:1
+  --> $DIR/feature-gate-abi.rs:22:8
    |
 LL | extern "thiscall" fn f8() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
    |
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:23:1
+  --> $DIR/feature-gate-abi.rs:23:8
    |
 LL | extern "amdgpu-kernel" fn f9() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:24:1
+  --> $DIR/feature-gate-abi.rs:24:8
    |
 LL | extern "efiapi" fn f10() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/65815
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:28:5
+  --> $DIR/feature-gate-abi.rs:28:12
    |
 LL |     extern "rust-intrinsic" fn m1();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:30:5
+  --> $DIR/feature-gate-abi.rs:30:12
    |
 LL |     extern "platform-intrinsic" fn m2();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/27731
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:32:5
+  --> $DIR/feature-gate-abi.rs:32:12
    |
 LL |     extern "vectorcall" fn m3();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:33:5
+  --> $DIR/feature-gate-abi.rs:33:12
    |
 LL |     extern "rust-call" fn m4();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:34:5
+  --> $DIR/feature-gate-abi.rs:34:12
    |
 LL |     extern "msp430-interrupt" fn m5();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:35:5
+  --> $DIR/feature-gate-abi.rs:35:12
    |
 LL |     extern "ptx-kernel" fn m6();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38788
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:36:5
+  --> $DIR/feature-gate-abi.rs:36:12
    |
 LL |     extern "x86-interrupt" fn m7();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/40180
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:37:5
+  --> $DIR/feature-gate-abi.rs:37:12
    |
 LL |     extern "thiscall" fn m8();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^
    |
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:38:5
+  --> $DIR/feature-gate-abi.rs:38:12
    |
 LL |     extern "amdgpu-kernel" fn m9();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:39:5
+  --> $DIR/feature-gate-abi.rs:39:12
    |
 LL |     extern "efiapi" fn m10();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/65815
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:41:5
+  --> $DIR/feature-gate-abi.rs:41:12
    |
 LL |     extern "vectorcall" fn dm3() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:42:5
+  --> $DIR/feature-gate-abi.rs:42:12
    |
 LL |     extern "rust-call" fn dm4() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:43:5
+  --> $DIR/feature-gate-abi.rs:43:12
    |
 LL |     extern "msp430-interrupt" fn dm5() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:44:5
+  --> $DIR/feature-gate-abi.rs:44:12
    |
 LL |     extern "ptx-kernel" fn dm6() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38788
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:45:5
+  --> $DIR/feature-gate-abi.rs:45:12
    |
 LL |     extern "x86-interrupt" fn dm7() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/40180
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:46:5
+  --> $DIR/feature-gate-abi.rs:46:12
    |
 LL |     extern "thiscall" fn dm8() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^
    |
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:47:5
+  --> $DIR/feature-gate-abi.rs:47:12
    |
 LL |     extern "amdgpu-kernel" fn dm9() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:48:5
+  --> $DIR/feature-gate-abi.rs:48:12
    |
 LL |     extern "efiapi" fn dm10() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/65815
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:55:5
+  --> $DIR/feature-gate-abi.rs:55:12
    |
 LL |     extern "rust-intrinsic" fn m1() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:57:5
+  --> $DIR/feature-gate-abi.rs:57:12
    |
 LL |     extern "platform-intrinsic" fn m2() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/27731
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:59:5
+  --> $DIR/feature-gate-abi.rs:59:12
    |
 LL |     extern "vectorcall" fn m3() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:60:5
+  --> $DIR/feature-gate-abi.rs:60:12
    |
 LL |     extern "rust-call" fn m4() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:61:5
+  --> $DIR/feature-gate-abi.rs:61:12
    |
 LL |     extern "msp430-interrupt" fn m5() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:62:5
+  --> $DIR/feature-gate-abi.rs:62:12
    |
 LL |     extern "ptx-kernel" fn m6() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38788
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:63:5
+  --> $DIR/feature-gate-abi.rs:63:12
    |
 LL |     extern "x86-interrupt" fn m7() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/40180
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:64:5
+  --> $DIR/feature-gate-abi.rs:64:12
    |
 LL |     extern "thiscall" fn m8() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^
    |
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:65:5
+  --> $DIR/feature-gate-abi.rs:65:12
    |
 LL |     extern "amdgpu-kernel" fn m9() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:66:5
+  --> $DIR/feature-gate-abi.rs:66:12
    |
 LL |     extern "efiapi" fn m10() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/65815
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:71:5
+  --> $DIR/feature-gate-abi.rs:71:12
    |
 LL |     extern "rust-intrinsic" fn im1() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:73:5
+  --> $DIR/feature-gate-abi.rs:73:12
    |
 LL |     extern "platform-intrinsic" fn im2() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/27731
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:75:5
+  --> $DIR/feature-gate-abi.rs:75:12
    |
 LL |     extern "vectorcall" fn im3() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:76:5
+  --> $DIR/feature-gate-abi.rs:76:12
    |
 LL |     extern "rust-call" fn im4() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:77:5
+  --> $DIR/feature-gate-abi.rs:77:12
    |
 LL |     extern "msp430-interrupt" fn im5() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:78:5
+  --> $DIR/feature-gate-abi.rs:78:12
    |
 LL |     extern "ptx-kernel" fn im6() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38788
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:79:5
+  --> $DIR/feature-gate-abi.rs:79:12
    |
 LL |     extern "x86-interrupt" fn im7() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/40180
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:80:5
+  --> $DIR/feature-gate-abi.rs:80:12
    |
 LL |     extern "thiscall" fn im8() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^
    |
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:81:5
+  --> $DIR/feature-gate-abi.rs:81:12
    |
 LL |     extern "amdgpu-kernel" fn im9() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:82:5
+  --> $DIR/feature-gate-abi.rs:82:12
    |
 LL |     extern "efiapi" fn im10() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/65815
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:86:11
+  --> $DIR/feature-gate-abi.rs:86:18
    |
 LL | type A1 = extern "rust-intrinsic" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:87:11
+  --> $DIR/feature-gate-abi.rs:87:18
    |
 LL | type A2 = extern "platform-intrinsic" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/27731
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:88:11
+  --> $DIR/feature-gate-abi.rs:88:18
    |
 LL | type A3 = extern "vectorcall" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:89:11
+  --> $DIR/feature-gate-abi.rs:89:18
    |
 LL | type A4 = extern "rust-call" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:90:11
+  --> $DIR/feature-gate-abi.rs:90:18
    |
 LL | type A5 = extern "msp430-interrupt" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:91:11
+  --> $DIR/feature-gate-abi.rs:91:18
    |
 LL | type A6 = extern "ptx-kernel" fn ();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38788
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:92:11
+  --> $DIR/feature-gate-abi.rs:92:18
    |
 LL | type A7 = extern "x86-interrupt" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/40180
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:93:11
+  --> $DIR/feature-gate-abi.rs:93:18
    |
 LL | type A8 = extern "thiscall" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^
    |
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:94:11
+  --> $DIR/feature-gate-abi.rs:94:18
    |
 LL | type A9 = extern "amdgpu-kernel" fn();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:95:12
+  --> $DIR/feature-gate-abi.rs:95:19
    |
 LL | type A10 = extern "efiapi" fn();
-   |            ^^^^^^^^^^^^^^^^^^^^
+   |                   ^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/65815
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:98:1
+  --> $DIR/feature-gate-abi.rs:98:8
    |
 LL | extern "rust-intrinsic" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:99:1
+  --> $DIR/feature-gate-abi.rs:99:8
    |
 LL | extern "platform-intrinsic" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/27731
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:100:1
+  --> $DIR/feature-gate-abi.rs:100:8
    |
 LL | extern "vectorcall" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:101:1
+  --> $DIR/feature-gate-abi.rs:101:8
    |
 LL | extern "rust-call" {}
-   | ^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:102:1
+  --> $DIR/feature-gate-abi.rs:102:8
    |
 LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38487
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:103:1
+  --> $DIR/feature-gate-abi.rs:103:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/38788
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:104:1
+  --> $DIR/feature-gate-abi.rs:104:8
    |
 LL | extern "x86-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/40180
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:105:1
+  --> $DIR/feature-gate-abi.rs:105:8
    |
 LL | extern "thiscall" {}
-   | ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
    |
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:106:1
+  --> $DIR/feature-gate-abi.rs:106:8
    |
 LL | extern "amdgpu-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51575
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:107:1
+  --> $DIR/feature-gate-abi.rs:107:8
    |
 LL | extern "efiapi" {}
-   | ^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/65815
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
diff --git a/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr b/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr
index 4954a7d1f71..1757befec35 100644
--- a/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr
@@ -1,10 +1,8 @@
 error[E0658]: unadjusted ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi_unadjusted.rs:1:1
+  --> $DIR/feature-gate-abi_unadjusted.rs:1:8
    |
-LL | / extern "unadjusted" fn foo() {
-LL | |
-LL | | }
-   | |_^
+LL | extern "unadjusted" fn foo() {
+   |        ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_unadjusted)]` to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
index 101a10e8df7..8f943d357ce 100644
--- a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
+++ b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
@@ -1,18 +1,16 @@
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-intrinsics.rs:1:1
+  --> $DIR/feature-gate-intrinsics.rs:1:8
    |
-LL | / extern "rust-intrinsic" {
-LL | |     fn bar();
-LL | | }
-   | |_^
+LL | extern "rust-intrinsic" {
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-intrinsics.rs:5:1
+  --> $DIR/feature-gate-intrinsics.rs:5:8
    |
 LL | extern "rust-intrinsic" fn baz() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
index c05379c71ee..657bf13c873 100644
--- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
@@ -1,35 +1,35 @@
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:11:5
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:11:12
    |
 LL |     extern "rust-call" fn call(self, args: ()) -> () {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:17:5
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:17:12
    |
 LL |     extern "rust-call" fn call_once(self, args: ()) -> () {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:5
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:12
    |
 LL |     extern "rust-call" fn call_mut(&self, args: ()) -> () {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:29:5
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:29:12
    |
 LL |     extern "rust-call" fn call_once(&self, args: ()) -> () {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
index 723c6619887..f343a42eb8f 100644
--- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
@@ -1,10 +1,8 @@
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-unboxed-closures.rs:9:5
+  --> $DIR/feature-gate-unboxed-closures.rs:9:12
    |
-LL | /     extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 {
-LL | |         a + b
-LL | |     }
-   | |_____^
+LL |     extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 {
+   |            ^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr
index 129d7ef5783..151dc681621 100644
--- a/src/test/ui/impl-trait/trait_type.stderr
+++ b/src/test/ui/impl-trait/trait_type.stderr
@@ -29,7 +29,7 @@ error[E0046]: not all trait items implemented, missing: `fmt`
 LL | impl std::fmt::Display for MyType4 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation
    |
-   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+   = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { unimplemented!() }`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-3344.stderr b/src/test/ui/issues/issue-3344.stderr
index 6593e07b189..271fbb6c874 100644
--- a/src/test/ui/issues/issue-3344.stderr
+++ b/src/test/ui/issues/issue-3344.stderr
@@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `partial_cmp`
 LL | impl PartialOrd for Thing {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `partial_cmp` in implementation
    |
-   = note: `partial_cmp` from trait: `fn(&Self, &Rhs) -> std::option::Option<std::cmp::Ordering>`
+   = help: implement the missing item: `fn partial_cmp(&self, _: &Rhs) -> std::option::Option<std::cmp::Ordering> { unimplemented!() }`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/iterators/into-iter-on-arrays-lint.fixed b/src/test/ui/iterators/into-iter-on-arrays-lint.fixed
new file mode 100644
index 00000000000..f88a52d3159
--- /dev/null
+++ b/src/test/ui/iterators/into-iter-on-arrays-lint.fixed
@@ -0,0 +1,33 @@
+// run-pass
+// run-rustfix
+
+fn main() {
+    let small = [1, 2];
+    let big = [0u8; 33];
+
+    // Expressions that should trigger the lint
+    small.iter();
+    //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+    [1, 2].iter();
+    //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+    big.iter();
+    //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+    [0u8; 33].iter();
+    //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+
+
+    // Expressions that should not
+    (&[1, 2]).into_iter();
+    (&small).into_iter();
+    (&[0u8; 33]).into_iter();
+    (&big).into_iter();
+
+    for _ in &[1, 2] {}
+    (&small as &[_]).into_iter();
+    small[..].into_iter();
+    std::iter::IntoIterator::into_iter(&[1, 2]);
+}
diff --git a/src/test/ui/iterators/into-iter-on-arrays-lint.rs b/src/test/ui/iterators/into-iter-on-arrays-lint.rs
new file mode 100644
index 00000000000..e1a4b535f38
--- /dev/null
+++ b/src/test/ui/iterators/into-iter-on-arrays-lint.rs
@@ -0,0 +1,33 @@
+// run-pass
+// run-rustfix
+
+fn main() {
+    let small = [1, 2];
+    let big = [0u8; 33];
+
+    // Expressions that should trigger the lint
+    small.into_iter();
+    //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+    [1, 2].into_iter();
+    //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+    big.into_iter();
+    //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+    [0u8; 33].into_iter();
+    //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+
+
+    // Expressions that should not
+    (&[1, 2]).into_iter();
+    (&small).into_iter();
+    (&[0u8; 33]).into_iter();
+    (&big).into_iter();
+
+    for _ in &[1, 2] {}
+    (&small as &[_]).into_iter();
+    small[..].into_iter();
+    std::iter::IntoIterator::into_iter(&[1, 2]);
+}
diff --git a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr
new file mode 100644
index 00000000000..b5964bd44bf
--- /dev/null
+++ b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr
@@ -0,0 +1,37 @@
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+  --> $DIR/into-iter-on-arrays-lint.rs:9:11
+   |
+LL |     small.into_iter();
+   |           ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = note: `#[warn(array_into_iter)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
+
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+  --> $DIR/into-iter-on-arrays-lint.rs:12:12
+   |
+LL |     [1, 2].into_iter();
+   |            ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
+
+warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+  --> $DIR/into-iter-on-arrays-lint.rs:15:9
+   |
+LL |     big.into_iter();
+   |         ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
+
+warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+  --> $DIR/into-iter-on-arrays-lint.rs:18:15
+   |
+LL |     [0u8; 33].into_iter();
+   |               ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
+
diff --git a/src/test/ui/missing/missing-items/m2.stderr b/src/test/ui/missing/missing-items/m2.stderr
index d2dac4ca645..f8243528d72 100644
--- a/src/test/ui/missing/missing-items/m2.stderr
+++ b/src/test/ui/missing/missing-items/m2.stderr
@@ -4,9 +4,9 @@ error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `met
 LL | impl m1::X for X {
    | ^^^^^^^^^^^^^^^^ missing `CONSTANT`, `Type`, `method` in implementation
    |
-   = note: `CONSTANT` from trait: `const CONSTANT: u32;`
-   = note: `Type` from trait: `type Type;`
-   = note: `method` from trait: `fn(&Self, std::string::String) -> <Self as m1::X>::Type`
+   = help: implement the missing item: `const CONSTANT: u32 = 42;`
+   = help: implement the missing item: `type Type = Type;`
+   = help: implement the missing item: `fn method(&self, _: std::string::String) -> <Self as m1::X>::Type { unimplemented!() }`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs
index 9f301db0995..7db83674efc 100644
--- a/src/test/ui/parser/bad-lit-suffixes.rs
+++ b/src/test/ui/parser/bad-lit-suffixes.rs
@@ -1,9 +1,9 @@
 extern
-    "C"suffix //~ ERROR suffixes on an ABI spec are invalid
+    "C"suffix //~ ERROR suffixes on a string literal are invalid
     fn foo() {}
 
 extern
-    "C"suffix //~ ERROR suffixes on an ABI spec are invalid
+    "C"suffix //~ ERROR suffixes on a string literal are invalid
 {}
 
 fn main() {
diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr
index 208fcf43d91..6b0049298ff 100644
--- a/src/test/ui/parser/bad-lit-suffixes.stderr
+++ b/src/test/ui/parser/bad-lit-suffixes.stderr
@@ -1,10 +1,10 @@
-error: suffixes on an ABI spec are invalid
+error: suffixes on a string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:2:5
    |
 LL |     "C"suffix
    |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on an ABI spec are invalid
+error: suffixes on a string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:6:5
    |
 LL |     "C"suffix
diff --git a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs
new file mode 100644
index 00000000000..cb23f2c808c
--- /dev/null
+++ b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs
@@ -0,0 +1,26 @@
+// check-pass
+
+// In this test we check that the parser accepts an ABI string when it
+// comes from a macro `literal` fragment as opposed to a hardcoded string.
+
+fn main() {}
+
+macro_rules! abi_from_lit_frag {
+    ($abi:literal) => {
+        extern $abi {
+            fn _import();
+        }
+
+        extern $abi fn _export() {}
+
+        type _PTR = extern $abi fn();
+    }
+}
+
+mod rust {
+    abi_from_lit_frag!("Rust");
+}
+
+mod c {
+    abi_from_lit_frag!("C");
+}
diff --git a/src/test/ui/parser/extern-abi-raw-strings.rs b/src/test/ui/parser/extern-abi-raw-strings.rs
new file mode 100644
index 00000000000..fad855a21f6
--- /dev/null
+++ b/src/test/ui/parser/extern-abi-raw-strings.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+// Check that the string literal in `extern lit` will accept raw strings.
+
+fn main() {}
+
+extern r#"C"# fn foo() {}
+
+extern r#"C"# {
+    fn bar();
+}
+
+type T = extern r#"C"# fn();
diff --git a/src/test/ui/parser/extern-abi-string-escaping.rs b/src/test/ui/parser/extern-abi-string-escaping.rs
new file mode 100644
index 00000000000..87bd31aabb6
--- /dev/null
+++ b/src/test/ui/parser/extern-abi-string-escaping.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+// Check that the string literal in `extern lit` will escapes.
+
+fn main() {}
+
+extern "\x43" fn foo() {}
+
+extern "\x43" {
+    fn bar();
+}
+
+type T = extern "\x43" fn();
diff --git a/src/test/ui/parser/extern-abi-syntactic.rs b/src/test/ui/parser/extern-abi-syntactic.rs
new file mode 100644
index 00000000000..7d2bbfe8a01
--- /dev/null
+++ b/src/test/ui/parser/extern-abi-syntactic.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+// Check that from the grammar's point of view,
+// the specific set of ABIs is not part of it.
+
+fn main() {}
+
+#[cfg(FALSE)]
+extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn foo() {}
+
+#[cfg(FALSE)]
+extern "some_abi_that_we_are_sure_does_not_exist_semantically" {
+    fn foo();
+}
+
+#[cfg(FALSE)]
+type T = extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn();
diff --git a/src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs b/src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs
new file mode 100644
index 00000000000..9d68a7bffde
--- /dev/null
+++ b/src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+// Test that failing macro matchers will not cause pre-expansion errors
+// even though they use a feature that is pre-expansion gated.
+
+macro_rules! m {
+    ($e:expr) => { 0 }; // This fails on the input below due to `, foo`.
+    ($e:expr,) => { 1 }; // This also fails to match due to `foo`.
+    (box $e:expr, foo) => { 2 }; // Successful matcher, we should get `2`.
+}
+
+fn main() {
+    assert_eq!(2, m!(box 42, foo));
+}
diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr
index 81409aac289..f23f421edc7 100644
--- a/src/test/ui/span/impl-wrong-item-for-trait.stderr
+++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr
@@ -64,7 +64,7 @@ error[E0046]: not all trait items implemented, missing: `fmt`
 LL | impl Debug for FooTypeForMethod {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation
    |
-   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+   = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { unimplemented!() }`
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr
index 865fae917c5..f88ce6c88db 100644
--- a/src/test/ui/span/issue-23729.stderr
+++ b/src/test/ui/span/issue-23729.stderr
@@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Item`
 LL |         impl Iterator for Recurrence {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Item` in implementation
    |
-   = note: `Item` from trait: `type Item;`
+   = help: implement the missing item: `type Item = Type;`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr
index a8e3e9b6b9a..46a820f1b76 100644
--- a/src/test/ui/span/issue-23827.stderr
+++ b/src/test/ui/span/issue-23827.stderr
@@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Output`
 LL | impl<C: Component> FnOnce<(C,)> for Prototype {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Output` in implementation
    |
-   = note: `Output` from trait: `type Output;`
+   = help: implement the missing item: `type Output = Type;`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr
index 4827e9ddd50..a1f9b255020 100644
--- a/src/test/ui/span/issue-24356.stderr
+++ b/src/test/ui/span/issue-24356.stderr
@@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Target`
 LL |         impl Deref for Thing {
    |         ^^^^^^^^^^^^^^^^^^^^ missing `Target` in implementation
    |
-   = note: `Target` from trait: `type Target;`
+   = help: implement the missing item: `type Target = Type;`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/missing-trait-item.fixed b/src/test/ui/suggestions/missing-trait-item.fixed
new file mode 100644
index 00000000000..42f579a665e
--- /dev/null
+++ b/src/test/ui/suggestions/missing-trait-item.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+
+trait T {
+    unsafe fn foo(a: &usize, b: &usize) -> usize;
+    fn bar(&self, a: &usize, b: &usize) -> usize;
+}
+
+mod foo {
+    use super::T;
+    impl T for () {    fn bar(&self, _: &usize, _: &usize) -> usize { unimplemented!() }
+        unsafe fn foo(_: &usize, _: &usize) -> usize { unimplemented!() }
+    } //~ ERROR not all trait items
+
+    impl T for usize { //~ ERROR not all trait items
+        fn bar(&self, _: &usize, _: &usize) -> usize { unimplemented!() }
+        unsafe fn foo(_: &usize, _: &usize) -> usize { unimplemented!() }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-trait-item.rs b/src/test/ui/suggestions/missing-trait-item.rs
new file mode 100644
index 00000000000..b4fca25ba2f
--- /dev/null
+++ b/src/test/ui/suggestions/missing-trait-item.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+
+trait T {
+    unsafe fn foo(a: &usize, b: &usize) -> usize;
+    fn bar(&self, a: &usize, b: &usize) -> usize;
+}
+
+mod foo {
+    use super::T;
+    impl T for () {} //~ ERROR not all trait items
+
+    impl T for usize { //~ ERROR not all trait items
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-trait-item.stderr b/src/test/ui/suggestions/missing-trait-item.stderr
new file mode 100644
index 00000000000..4a9d7b472c9
--- /dev/null
+++ b/src/test/ui/suggestions/missing-trait-item.stderr
@@ -0,0 +1,25 @@
+error[E0046]: not all trait items implemented, missing: `foo`, `bar`
+  --> $DIR/missing-trait-item.rs:10:5
+   |
+LL |     unsafe fn foo(a: &usize, b: &usize) -> usize;
+   |     --------------------------------------------- `foo` from trait
+LL |     fn bar(&self, a: &usize, b: &usize) -> usize;
+   |     --------------------------------------------- `bar` from trait
+...
+LL |     impl T for () {}
+   |     ^^^^^^^^^^^^^ missing `foo`, `bar` in implementation
+
+error[E0046]: not all trait items implemented, missing: `foo`, `bar`
+  --> $DIR/missing-trait-item.rs:12:5
+   |
+LL |     unsafe fn foo(a: &usize, b: &usize) -> usize;
+   |     --------------------------------------------- `foo` from trait
+LL |     fn bar(&self, a: &usize, b: &usize) -> usize;
+   |     --------------------------------------------- `bar` from trait
+...
+LL |     impl T for usize {
+   |     ^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0046`.