Rollup merge of #64283 - XAMPPRocky:master, r=Mark-Simulacrum

Updated RELEASES.md for 1.38.0

### [Rendered](https://github.com/XAMPPRocky/rust/blob/master/RELEASES.md)

r? @Mark-Simulacrum
cc @rust-lang/release
diff --git a/.mailmap b/.mailmap
index da8044d..9587aaa 100644
--- a/.mailmap
+++ b/.mailmap
@@ -184,6 +184,7 @@
 Nick Platt <platt.nicholas@gmail.com>
 Nicole Mazzuca <npmazzuca@gmail.com>
 Nif Ward <nif.ward@gmail.com>
+Oliver Middleton <olliemail27@gmail.com> <ollie27@users.noreply.github.com>
 Oliver Scherer <oliver.schneider@kit.edu> <git-spam-no-reply9815368754983@oli-obk.de>
 Oliver Scherer <oliver.schneider@kit.edu> <git-spam9815368754983@oli-obk.de>
 Oliver Scherer <oliver.schneider@kit.edu> <github333195615777966@oli-obk.de>
diff --git a/Cargo.lock b/Cargo.lock
index 108c2fb..326f3b1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -109,9 +109,9 @@
 
 [[package]]
 name = "backtrace"
-version = "0.3.35"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55"
+checksum = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2"
 dependencies = [
  "backtrace-sys",
  "cfg-if",
@@ -223,18 +223,18 @@
 
 [[package]]
 name = "bytecount"
-version = "0.5.1"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c"
+checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
 dependencies = [
  "packed_simd",
 ]
 
 [[package]]
 name = "byteorder"
-version = "1.2.7"
+version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
+checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
 
 [[package]]
 name = "bytes"
@@ -287,7 +287,7 @@
  "git2-curl",
  "glob",
  "hex",
- "home 0.5.0",
+ "home",
  "ignore",
  "im-rc",
  "jobserver",
@@ -309,7 +309,7 @@
  "same-file",
  "semver",
  "serde",
- "serde_ignored 0.1.0",
+ "serde_ignored",
  "serde_json",
  "shell-escape",
  "strip-ansi-escapes",
@@ -392,9 +392,9 @@
 
 [[package]]
 name = "clap"
-version = "2.32.0"
+version = "2.33.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
+checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
 dependencies = [
  "ansi_term",
  "atty",
@@ -753,9 +753,9 @@
 dependencies = [
  "fnv",
  "ident_case",
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -765,8 +765,8 @@
 checksum = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1"
 dependencies = [
  "darling_core",
- "quote",
- "syn",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -781,9 +781,9 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ca414e896ae072546f4d789f452daaecf60ddee4c9df5dc6d5936d769e3d87c"
 dependencies = [
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -792,10 +792,10 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871"
 dependencies = [
- "proc-macro2",
- "quote",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
  "rustc_version",
- "syn",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -953,9 +953,9 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
 dependencies = [
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
  "synstructure",
 ]
 
@@ -1139,12 +1139,13 @@
 
 [[package]]
 name = "getrandom"
-version = "0.1.8"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49"
+checksum = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
 dependencies = [
  "cfg-if",
  "libc",
+ "wasi",
 ]
 
 [[package]]
@@ -1261,16 +1262,6 @@
 
 [[package]]
 name = "home"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80dff82fb58cfbbc617fb9a9184b010be0529201553cda50ad04372bc2333aff"
-dependencies = [
- "scopeguard 0.3.3",
- "winapi 0.3.6",
-]
-
-[[package]]
-name = "home"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c07c315e106bd6f83f026a20ddaeef2706782e490db1dcdd37caad38a0e895b3"
@@ -1288,9 +1279,9 @@
  "log",
  "mac",
  "markup5ever",
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -1529,10 +1520,29 @@
 checksum = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be"
 
 [[package]]
-name = "jsonrpc-core"
-version = "12.0.0"
+name = "jsonrpc-client-transports"
+version = "13.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "288dca7f9713710a29e485076b9340156cb701edb46a881f5d0c31aa4f5b9143"
+checksum = "39577db48b004cffb4c5b8e5c9b993c177c52599ecbee88711e815acf65144db"
+dependencies = [
+ "failure",
+ "futures",
+ "jsonrpc-core",
+ "jsonrpc-pubsub",
+ "jsonrpc-server-utils",
+ "log",
+ "parity-tokio-ipc",
+ "serde",
+ "serde_json",
+ "tokio",
+ "url 1.7.2",
+]
+
+[[package]]
+name = "jsonrpc-core"
+version = "13.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd42951eb35079520ee29b7efbac654d85821b397ef88c8151600ef7e2d00217"
 dependencies = [
  "futures",
  "log",
@@ -1542,6 +1552,70 @@
 ]
 
 [[package]]
+name = "jsonrpc-core-client"
+version = "13.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f047c10738edee7c3c6acf5241a0ce33df32ef9230c1a7fb03e4a77ee72c992f"
+dependencies = [
+ "jsonrpc-client-transports",
+]
+
+[[package]]
+name = "jsonrpc-derive"
+version = "13.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29f9149f785deaae92a4c834a9a1a83a4313b8cfedccf15362cd4cf039a64501"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
+]
+
+[[package]]
+name = "jsonrpc-ipc-server"
+version = "13.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "256c5e4292c17b4c2ecdf542299dc8e9d6b3939c075c54825570ad9317fe5751"
+dependencies = [
+ "jsonrpc-core",
+ "jsonrpc-server-utils",
+ "log",
+ "parity-tokio-ipc",
+ "parking_lot 0.9.0",
+ "tokio-service",
+]
+
+[[package]]
+name = "jsonrpc-pubsub"
+version = "13.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2c08b444cc0ed70263798834343d0ac875e664257df8079160f23ac1ea79446"
+dependencies = [
+ "jsonrpc-core",
+ "log",
+ "parking_lot 0.9.0",
+ "serde",
+]
+
+[[package]]
+name = "jsonrpc-server-utils"
+version = "13.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44561bfdd31401bad790527f1e951dde144f2341ddc3e1b859d32945e1a34eff"
+dependencies = [
+ "bytes",
+ "globset",
+ "jsonrpc-core",
+ "lazy_static 1.3.0",
+ "log",
+ "num_cpus",
+ "tokio",
+ "tokio-codec",
+ "unicase 2.4.0",
+]
+
+[[package]]
 name = "kernel32-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1571,9 +1645,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.61"
+version = "0.2.62"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa"
+checksum = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -1656,6 +1730,15 @@
 ]
 
 [[package]]
+name = "lock_api"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
+dependencies = [
+ "scopeguard 1.0.0",
+]
+
+[[package]]
 name = "log"
 version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1686,18 +1769,15 @@
 
 [[package]]
 name = "lsp-types"
-version = "0.57.2"
+version = "0.60.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b62b77309737b1e262b3bbf37ff8faa740562c633b14702afe9be85dbcb6f88a"
+checksum = "fe3edefcd66dde1f7f1df706f46520a3c93adc5ca4bc5747da6621195e894efd"
 dependencies = [
  "bitflags",
- "num-derive",
- "num-traits",
  "serde",
- "serde_derive",
  "serde_json",
- "url 1.7.2",
- "url_serde",
+ "serde_repr",
+ "url 2.1.0",
 ]
 
 [[package]]
@@ -1800,7 +1880,7 @@
  "serde",
  "serde_derive",
  "serde_json",
- "structopt",
+ "structopt 0.2.18",
  "url 1.7.2",
 ]
 
@@ -1985,7 +2065,7 @@
  "hex",
  "log",
  "num-traits",
- "rand 0.6.1",
+ "rand 0.7.0",
  "rustc-workspace-hack",
  "rustc_version",
  "shell-escape",
@@ -2034,18 +2114,6 @@
 checksum = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 
 [[package]]
-name = "num-derive"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d"
-dependencies = [
- "num-traits",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
 name = "num-integer"
 version = "0.1.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2070,6 +2138,12 @@
 ]
 
 [[package]]
+name = "once_cell"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6a04cb71e910d0034815600180f62a95bf6e67942d7ab52a166a68c7d7e9cd0"
+
+[[package]]
 name = "open"
 version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2106,9 +2180,9 @@
 
 [[package]]
 name = "openssl-src"
-version = "111.3.0+1.1.1c"
+version = "111.6.0+1.1.1d"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53ed5f31d294bdf5f7a4ba0a206c2754b0f60e9a63b7e3076babc5317873c797"
+checksum = "b9c2da1de8a7a3f860919c01540b03a6db16de042405a8a07a5e9d0b4b825d9c"
 dependencies = [
  "cc",
 ]
@@ -2179,13 +2253,42 @@
 ]
 
 [[package]]
+name = "parity-tokio-ipc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8281bf4f1d6429573f89589bf68d89451c46750977a8264f8ea3edbabeba7947"
+dependencies = [
+ "bytes",
+ "futures",
+ "log",
+ "mio-named-pipes",
+ "miow 0.3.3",
+ "rand 0.7.0",
+ "tokio",
+ "tokio-named-pipes",
+ "tokio-uds",
+ "winapi 0.3.6",
+]
+
+[[package]]
 name = "parking_lot"
 version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
 dependencies = [
- "lock_api",
- "parking_lot_core",
+ "lock_api 0.1.3",
+ "parking_lot_core 0.4.0",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
+dependencies = [
+ "lock_api 0.3.1",
+ "parking_lot_core 0.6.2",
+ "rustc_version",
 ]
 
 [[package]]
@@ -2202,6 +2305,21 @@
 ]
 
 [[package]]
+name = "parking_lot_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
+dependencies = [
+ "cfg-if",
+ "cloudabi",
+ "libc",
+ "redox_syscall",
+ "rustc_version",
+ "smallvec",
+ "winapi 0.3.6",
+]
+
+[[package]]
 name = "percent-encoding"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2240,9 +2358,9 @@
 dependencies = [
  "pest",
  "pest_meta",
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -2356,6 +2474,26 @@
 ]
 
 [[package]]
+name = "proc-macro-crate"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e"
+dependencies = [
+ "toml",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097"
+dependencies = [
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.5",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "0.4.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2365,6 +2503,15 @@
 ]
 
 [[package]]
+name = "proc-macro2"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
+dependencies = [
+ "unicode-xid 0.2.0",
+]
+
+[[package]]
 name = "proc_macro"
 version = "0.0.0"
 dependencies = [
@@ -2416,14 +2563,23 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
 dependencies = [
- "proc-macro2",
+ "proc-macro2 0.4.30",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+dependencies = [
+ "proc-macro2 1.0.3",
 ]
 
 [[package]]
 name = "racer"
-version = "2.1.25"
+version = "2.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0727b9d7baaf9e42851145545d7b980b5c1752bd16a4c77c925c5e573d0069d9"
+checksum = "dde22b84ab75220015cbd91240222402bf885cbe3a5dc856475771abb82533ae"
 dependencies = [
  "bitflags",
  "clap",
@@ -2715,7 +2871,7 @@
 
 [[package]]
 name = "rls"
-version = "1.38.0"
+version = "1.39.0"
 dependencies = [
  "cargo",
  "cargo_metadata",
@@ -2726,7 +2882,7 @@
  "failure",
  "futures",
  "heck",
- "home 0.3.3",
+ "home",
  "itertools 0.8.0",
  "jsonrpc-core",
  "lazy_static 1.3.0",
@@ -2741,6 +2897,7 @@
  "regex",
  "rls-analysis",
  "rls-data",
+ "rls-ipc",
  "rls-rustc",
  "rls-span",
  "rls-vfs",
@@ -2750,14 +2907,14 @@
  "rustfmt-nightly",
  "serde",
  "serde_derive",
- "serde_ignored 0.0.4",
+ "serde_ignored",
  "serde_json",
  "tempfile",
  "tokio",
  "tokio-process",
  "tokio-timer",
  "toml",
- "url 1.7.2",
+ "url 2.1.0",
  "walkdir",
 ]
 
@@ -2789,8 +2946,32 @@
 ]
 
 [[package]]
+name = "rls-ipc"
+version = "0.1.0"
+dependencies = [
+ "jsonrpc-core",
+ "jsonrpc-core-client",
+ "jsonrpc-derive",
+ "jsonrpc-ipc-server",
+ "rls-data",
+ "serde",
+]
+
+[[package]]
 name = "rls-rustc"
 version = "0.6.0"
+dependencies = [
+ "clippy_lints",
+ "env_logger",
+ "failure",
+ "futures",
+ "log",
+ "rand 0.6.1",
+ "rls-data",
+ "rls-ipc",
+ "serde",
+ "tokio",
+]
 
 [[package]]
 name = "rls-span"
@@ -2833,11 +3014,10 @@
  "fmt_macros",
  "graphviz",
  "jobserver",
- "lazy_static 1.3.0",
  "log",
  "measureme",
  "num_cpus",
- "parking_lot",
+ "parking_lot 0.9.0",
  "polonius-engine",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -2856,9 +3036,9 @@
 
 [[package]]
 name = "rustc-ap-arena"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dc2e1e68b64268c543bfa6e63e3c0d9ea58074c71396f42f76931f35a9287f9"
+checksum = "f59b76d334bd533f3fdc5c651c27678c5e80fac67c6f7da22ba21a58878c55f5"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "smallvec",
@@ -2866,15 +3046,15 @@
 
 [[package]]
 name = "rustc-ap-graphviz"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c108d647ce0dd46477b048eafff5a6273b5652e02d47424b0cd684147379c811"
+checksum = "3e632ef08ca17458acfd46d2ead3d541a1c249586cd5329f5fe333dacfab6142"
 
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "656771744e0783cb8e4481e3b8b1f975687610aaf18833b898018111a0e0e582"
+checksum = "e89e2c7be68185418f3cd56af3df8b29007a59a1cebefa63612d055f9bcb1a36"
 dependencies = [
  "cfg-if",
  "crossbeam-utils 0.6.5",
@@ -2883,7 +3063,7 @@
  "jobserver",
  "lazy_static 1.3.0",
  "log",
- "parking_lot",
+ "parking_lot 0.7.1",
  "rustc-ap-graphviz",
  "rustc-ap-serialize",
  "rustc-hash",
@@ -2895,9 +3075,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e37064f6624bc799bfaa2968b61ee6880926dea2a8bba69f18aef6c8e69c9604"
+checksum = "1e47cb380abeb72b01e42b2342d592f7eeea7d536c2f1f0d0e550dc509e46333"
 dependencies = [
  "annotate-snippets",
  "atty",
@@ -2905,34 +3085,38 @@
  "rustc-ap-rustc_data_structures",
  "rustc-ap-serialize",
  "rustc-ap-syntax_pos",
+ "term_size",
  "termcolor",
  "unicode-width",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef5bc0a971823637ea23a857f0ef1467f44b1e05d71968821f83a0abe53e0fe3"
+checksum = "494cfaf67f49217d67d0774eeecbba61ac89acf478db97ef11f113ed8a959305"
+dependencies = [
+ "unicode-xid 0.2.0",
+]
 
 [[package]]
 name = "rustc-ap-rustc_macros"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b90037e3336fe8835f468db44d0848ae10d9cc8533ae89b55828883f905b7e80"
+checksum = "e2e5d36becc59b4497f9cbd3ae0610081de0207a1d0e95c066369167b14f486f"
 dependencies = [
  "itertools 0.8.0",
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
  "synstructure",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_target"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cadf9ca07315eab3a7a21f63872f9cc81e250fd6ede0419c24f8926ade73a45d"
+checksum = "a7bfc5f96dfc3b9f8d5b57884f7f37467ecff6776cd4b8b491a7daece6fdd7c2"
 dependencies = [
  "bitflags",
  "log",
@@ -2943,9 +3127,9 @@
 
 [[package]]
 name = "rustc-ap-serialize"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61673783f2089e01033ffa82d1988f55175402071b31253a358292e1624d4602"
+checksum = "2bb9ee231cf79eded39c56647499f83d6136ff5c8c0baaa9e21b6febee00f4f6"
 dependencies = [
  "indexmap",
  "smallvec",
@@ -2953,9 +3137,9 @@
 
 [[package]]
 name = "rustc-ap-syntax"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28f3dd1346d5b0269c07a4a78855e309a298ab569c9c1302d4d4f57f8eee4e84"
+checksum = "b3827fc208814efbde82d613e31d11b4250ce9e8cf8afe4a4d47bbbd099632c9"
 dependencies = [
  "bitflags",
  "lazy_static 1.3.0",
@@ -2973,9 +3157,9 @@
 
 [[package]]
 name = "rustc-ap-syntax_pos"
-version = "546.0.0"
+version = "583.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45e67b526dbda3a0c7dab91c8947d43685e7697f52686a4949da3c179cd7c979"
+checksum = "930ed81c34f325e512cc315c04d676fa84a373879d5c43bb54054a0522b05213"
 dependencies = [
  "cfg-if",
  "rustc-ap-arena",
@@ -3046,21 +3230,21 @@
 
 [[package]]
 name = "rustc-std-workspace-alloc"
-version = "1.0.0"
+version = "1.99.0"
 dependencies = [
  "alloc",
 ]
 
 [[package]]
 name = "rustc-std-workspace-core"
-version = "1.0.0"
+version = "1.99.0"
 dependencies = [
  "core",
 ]
 
 [[package]]
 name = "rustc-std-workspace-std"
-version = "1.0.0"
+version = "1.99.0"
 dependencies = [
  "std",
 ]
@@ -3069,15 +3253,10 @@
 name = "rustc-workspace-hack"
 version = "1.0.0"
 dependencies = [
- "byteorder",
  "crossbeam-utils 0.6.5",
- "parking_lot",
- "rand 0.6.1",
- "scopeguard 0.3.3",
  "serde",
  "serde_json",
  "smallvec",
- "syn",
  "winapi 0.3.6",
 ]
 
@@ -3131,7 +3310,7 @@
  "log",
  "memmap",
  "num_cpus",
- "parking_lot",
+ "parking_lot 0.9.0",
  "rustc",
  "rustc_apfloat",
  "rustc_codegen_utils",
@@ -3174,7 +3353,7 @@
  "jobserver",
  "lazy_static 1.3.0",
  "log",
- "parking_lot",
+ "parking_lot 0.9.0",
  "rustc-hash",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -3189,6 +3368,7 @@
 dependencies = [
  "env_logger",
  "graphviz",
+ "lazy_static 1.3.0",
  "log",
  "rustc",
  "rustc_ast_borrowck",
@@ -3232,7 +3412,7 @@
 dependencies = [
  "graphviz",
  "log",
- "rand 0.6.1",
+ "rand 0.7.0",
  "rustc",
  "rustc_data_structures",
  "rustc_fs_util",
@@ -3246,6 +3426,7 @@
 version = "0.0.0"
 dependencies = [
  "log",
+ "once_cell",
  "rustc",
  "rustc-rayon",
  "rustc_ast_borrowck",
@@ -3314,9 +3495,9 @@
 version = "0.1.0"
 dependencies = [
  "itertools 0.8.0",
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
  "synstructure",
 ]
 
@@ -3555,20 +3736,19 @@
 
 [[package]]
 name = "rustfmt-config_proc_macro"
-version = "0.1.2"
+version = "0.2.0"
 dependencies = [
- "proc-macro2",
- "quote",
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
  "serde",
- "syn",
+ "syn 1.0.5",
 ]
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.6"
+version = "1.4.8"
 dependencies = [
  "annotate-snippets",
- "atty",
  "bytecount",
  "cargo_metadata",
  "derive-new",
@@ -3589,7 +3769,7 @@
  "rustfmt-config_proc_macro",
  "serde",
  "serde_json",
- "structopt",
+ "structopt 0.3.1",
  "term 0.6.0",
  "toml",
  "unicode-segmentation",
@@ -3698,18 +3878,9 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "477b13b646f5b5b56fc95bedfc3b550d12141ce84f466f6c44b9a17589923885"
 dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_ignored"
-version = "0.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"
-dependencies = [
- "serde",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -3733,6 +3904,17 @@
 ]
 
 [[package]]
+name = "serde_repr"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
+dependencies = [
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.5",
+]
+
+[[package]]
 name = "serde_urlencoded"
 version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3848,7 +4030,7 @@
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
- "rand 0.6.1",
+ "rand 0.7.0",
  "rustc_asan",
  "rustc_lsan",
  "rustc_msan",
@@ -3889,8 +4071,8 @@
 dependencies = [
  "phf_generator",
  "phf_shared",
- "proc-macro2",
- "quote",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
  "string_cache_shared",
 ]
 
@@ -3911,9 +4093,9 @@
 
 [[package]]
 name = "strsim"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 
 [[package]]
 name = "structopt"
@@ -3922,7 +4104,17 @@
 checksum = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7"
 dependencies = [
  "clap",
- "structopt-derive",
+ "structopt-derive 0.2.18",
+]
+
+[[package]]
+name = "structopt"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ac9d6e93dd792b217bf89cda5c14566e3043960c6f9da890c2ba5d09d07804c"
+dependencies = [
+ "clap",
+ "structopt-derive 0.3.1",
 ]
 
 [[package]]
@@ -3932,9 +4124,22 @@
 checksum = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107"
 dependencies = [
  "heck",
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ae9e5165d463a0dea76967d021f8d0f9316057bf5163aa2a4843790e842ff37"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.5",
 ]
 
 [[package]]
@@ -3950,9 +4155,9 @@
 checksum = "8baacebd7b7c9b864d83a6ba7a246232983e277b86fa5cdec77f565715a4b136"
 dependencies = [
  "heck",
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -3961,20 +4166,31 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3"
 dependencies = [
- "proc-macro2",
- "quote",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
  "unicode-xid 0.1.0",
 ]
 
 [[package]]
+name = "syn"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
+dependencies = [
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "unicode-xid 0.2.0",
+]
+
+[[package]]
 name = "synstructure"
 version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
 dependencies = [
- "proc-macro2",
- "quote",
- "syn",
+ "proc-macro2 0.4.30",
+ "quote 0.6.12",
+ "syn 0.15.35",
  "unicode-xid 0.1.0",
 ]
 
@@ -4044,13 +4260,13 @@
 
 [[package]]
 name = "tempfile"
-version = "3.0.5"
+version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2"
+checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
 dependencies = [
  "cfg-if",
  "libc",
- "rand 0.6.1",
+ "rand 0.7.0",
  "redox_syscall",
  "remove_dir_all",
  "winapi 0.3.6",
@@ -4154,9 +4370,9 @@
 
 [[package]]
 name = "textwrap"
-version = "0.10.0"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
 dependencies = [
  "unicode-width",
 ]
@@ -4280,6 +4496,19 @@
 ]
 
 [[package]]
+name = "tokio-named-pipes"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d282d483052288b2308ba5ee795f5673b159c9bdf63c385a05609da782a5eae"
+dependencies = [
+ "bytes",
+ "futures",
+ "mio",
+ "mio-named-pipes",
+ "tokio",
+]
+
+[[package]]
 name = "tokio-process"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4307,13 +4536,22 @@
  "log",
  "mio",
  "num_cpus",
- "parking_lot",
+ "parking_lot 0.7.1",
  "slab",
  "tokio-executor",
  "tokio-io",
 ]
 
 [[package]]
+name = "tokio-service"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
+dependencies = [
+ "futures",
+]
+
+[[package]]
 name = "tokio-signal"
 version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4436,8 +4674,8 @@
 checksum = "3c99ca245ec273c7e75c8ee58f47b882d0146f3c2c8495158082c6671e8b5335"
 dependencies = [
  "darling",
- "quote",
- "syn",
+ "quote 0.6.12",
+ "syn 0.15.35",
 ]
 
 [[package]]
@@ -4575,16 +4813,6 @@
 ]
 
 [[package]]
-name = "url_serde"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"
-dependencies = [
- "serde",
- "url 1.7.2",
-]
-
-[[package]]
 name = "utf-8"
 version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/config.toml.example b/config.toml.example
index 30e2ee1..848147c 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -184,7 +184,7 @@
 # default.
 #extended = false
 
-# Installs chosen set of extended tools if enables. By default builds all.
+# Installs chosen set of extended tools if enabled. By default builds all.
 # If chosen tool failed to build the installation fails.
 #tools = ["cargo", "rls", "clippy", "rustfmt", "analysis", "src"]
 
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index e0e4c07..65129ee 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -523,6 +523,10 @@
         'value2'
         >>> rb.get_toml('key', 'c') is None
         True
+
+        >>> rb.config_toml = 'key1 = true'
+        >>> rb.get_toml("key1")
+        'true'
         """
 
         cur_section = None
@@ -571,6 +575,12 @@
 
         >>> RustBuild.get_string('    "devel"   ')
         'devel'
+        >>> RustBuild.get_string("    'devel'   ")
+        'devel'
+        >>> RustBuild.get_string('devel') is None
+        True
+        >>> RustBuild.get_string('    "devel   ')
+        ''
         """
         start = line.find('"')
         if start != -1:
@@ -698,6 +708,14 @@
         if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
                 self.get_toml('submodules') == "false":
             return
+
+        # check the existence of 'git' command
+        try:
+            subprocess.check_output(['git', '--version'])
+        except (subprocess.CalledProcessError, OSError):
+            print("error: `git` is not found, please make sure it's installed and in the path.")
+            sys.exit(1)
+
         slow_submodules = self.get_toml('fast-submodules') == "false"
         start_time = time()
         if slow_submodules:
@@ -822,13 +840,13 @@
     except (OSError, IOError):
         pass
 
-    match = re.search(r'\nverbose = (\d+)', build.config_toml)
-    if match is not None:
-        build.verbose = max(build.verbose, int(match.group(1)))
+    config_verbose = build.get_toml('verbose', 'build')
+    if config_verbose is not None:
+        build.verbose = max(build.verbose, int(config_verbose))
 
-    build.use_vendored_sources = '\nvendor = true' in build.config_toml
+    build.use_vendored_sources = build.get_toml('vendor', 'build') == 'true'
 
-    build.use_locked_deps = '\nlocked-deps = true' in build.config_toml
+    build.use_locked_deps = build.get_toml('locked-deps', 'build') == 'true'
 
     build.check_vendored_status()
 
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 4f5de1e..b7873fd 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1167,6 +1167,8 @@
             cargo.arg("--frozen");
         }
 
+        cargo.env("RUSTC_INSTALL_BINDIR", &self.config.bindir);
+
         self.ci_env.force_coloring_in_ci(&mut cargo);
 
         cargo
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 43d9264..52b5cd8 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -137,7 +137,7 @@
     pub sysconfdir: Option<PathBuf>,
     pub datadir: Option<PathBuf>,
     pub docdir: Option<PathBuf>,
-    pub bindir: Option<PathBuf>,
+    pub bindir: PathBuf,
     pub libdir: Option<PathBuf>,
     pub mandir: Option<PathBuf>,
     pub codegen_tests: bool,
@@ -400,6 +400,7 @@
         config.incremental = flags.incremental;
         config.dry_run = flags.dry_run;
         config.keep_stage = flags.keep_stage;
+        config.bindir = "bin".into(); // default
         if let Some(value) = flags.deny_warnings {
             config.deny_warnings = value;
         }
@@ -482,7 +483,7 @@
             config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from);
             config.datadir = install.datadir.clone().map(PathBuf::from);
             config.docdir = install.docdir.clone().map(PathBuf::from);
-            config.bindir = install.bindir.clone().map(PathBuf::from);
+            set(&mut config.bindir, install.bindir.clone().map(PathBuf::from));
             config.libdir = install.libdir.clone().map(PathBuf::from);
             config.mandir = install.mandir.clone().map(PathBuf::from);
         }
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 5575867..384219c 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -67,7 +67,6 @@
     let sysconfdir_default = PathBuf::from("/etc");
     let datadir_default = PathBuf::from("share");
     let docdir_default = datadir_default.join("doc/rust");
-    let bindir_default = PathBuf::from("bin");
     let libdir_default = PathBuf::from("lib");
     let mandir_default = datadir_default.join("man");
     let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
@@ -76,7 +75,7 @@
     let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
     let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
     let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
-    let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default);
+    let bindir = &builder.config.bindir;
     let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
     let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);
 
diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml
index 77c9cda..1656066 100644
--- a/src/ci/azure-pipelines/auto.yml
+++ b/src/ci/azure-pipelines/auto.yml
@@ -236,10 +236,16 @@
         MSYS_BITS: 32
         RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
         SCRIPT: make ci-subset-1
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
       i686-msvc-2:
         MSYS_BITS: 32
         RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
         SCRIPT: make ci-subset-2
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
       # MSVC aux tests
       x86_64-msvc-aux:
         MSYS_BITS: 64
@@ -250,6 +256,9 @@
         SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
         RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
         VCVARS_BAT: vcvars64.bat
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
       # MSVC tools tests
       x86_64-msvc-tools:
         MSYS_BITS: 64
diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml
index ac6b344..da0a899 100644
--- a/src/ci/azure-pipelines/steps/run.yml
+++ b/src/ci/azure-pipelines/steps/run.yml
@@ -147,8 +147,15 @@
     git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
     cd rust-toolstate
     python2.7 "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" ""
+    # Only check maintainers if this build is supposed to publish toolstate.
+    # Builds that are not supposed to publish don't have the access token.
+    if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
+      TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py"
+    fi
     cd ..
     rm -rf rust-toolstate
+  env:
+    TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
   condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['IMAGE'], 'mingw-check'))
   displayName: Verify the publish_toolstate script works
 
diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile
index 2041ba5..517b59c 100644
--- a/src/ci/docker/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/i686-gnu-nopt/Dockerfile
@@ -19,3 +19,6 @@
 
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
 ENV SCRIPT python2.7 ../x.py test
+
+# FIXME(#59637) takes too long on CI right now
+ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile
index 17441dd..03db3ba 100644
--- a/src/ci/docker/i686-gnu/Dockerfile
+++ b/src/ci/docker/i686-gnu/Dockerfile
@@ -25,3 +25,6 @@
   --exclude src/test/rustdoc-js \
   --exclude src/tools/error_index_generator \
   --exclude src/tools/linkchecker
+
+# FIXME(#59637) takes too long on CI right now
+ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/doc/reference b/src/doc/reference
index 090c015..1944efe 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 090c015f7939665866432c334957bd536c811870
+Subproject commit 1944efed35989ba57fa397c0724c4921310311fc
diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide
index 6e25a3d..941968d 160000
--- a/src/doc/rustc-guide
+++ b/src/doc/rustc-guide
@@ -1 +1 @@
-Subproject commit 6e25a3d0d3573eb42b2e2339f1219e969d1b3dee
+Subproject commit 941968db2fd9c85788a4f971c8e425d46b4cb734
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 993fc84..49d05b5 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -471,3 +471,53 @@
 
 Public items that are not documented can be seen with the built-in `missing_docs` lint. Private
 items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint.
+
+### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc src/lib.rs -Z unstable-options --enable-per-target-ignores
+```
+
+This flag allows you to tag doctests with compiltest style `ignore-foo` filters that prevent
+rustdoc from running that test if the target triple string contains foo. For example:
+
+```rust
+///```ignore-foo,ignore-bar
+///assert!(2 == 2);
+///```
+struct Foo;
+```
+
+This will not be run when the build target is `super-awesome-foo` or `less-bar-awesome`.
+If the flag is not enabled, then rustdoc will consume the filter, but do nothing with it, and
+the above example will be run for all targets.
+If you want to preserve backwards compatibility for older versions of rustdoc, you can use
+
+```rust
+///```ignore,ignore-foo
+///assert!(2 == 2);
+///```
+struct Foo;
+```
+
+In older versions, this will be ignored on all targets, but on newer versions `ignore-gnu` will
+override `ignore`.
+
+### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it
+
+Using thses options looks like this:
+
+```bash
+$ rustdoc src/lib.rs -Z unstable-options --runtool runner --runtool-arg --do-thing --runtool-arg --do-other-thing
+```
+
+These options can be used to run the doctest under a program, and also pass arguments to
+that program. For example, if you want to run your doctests under valgrind you might run
+
+```bash
+$ rustdoc src/lib.rs -Z unstable-options --runtool valgrind
+```
+
+Another use case would be to run a test inside an emulator, or through a Virtual Machine.
diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py
index 537b419..7c2e914 100644
--- a/src/etc/lldb_batchmode.py
+++ b/src/etc/lldb_batchmode.py
@@ -45,7 +45,10 @@
 
 def breakpoint_callback(frame, bp_loc, dict):
     """This callback is registered with every breakpoint and makes sure that the
-    frame containing the breakpoint location is selected"""
+    frame containing the breakpoint location is selected """
+
+    # HACK(eddyb) print a newline to avoid continuing an unfinished line.
+    print("")
     print("Hit breakpoint " + str(bp_loc))
 
     # Select the frame and the thread containing it
diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs
index d3af910..0cb91ba 100644
--- a/src/liballoc/collections/btree/set.rs
+++ b/src/liballoc/collections/btree/set.rs
@@ -3,7 +3,7 @@
 
 use core::borrow::Borrow;
 use core::cmp::Ordering::{self, Less, Greater, Equal};
-use core::cmp::max;
+use core::cmp::{max, min};
 use core::fmt::{self, Debug};
 use core::iter::{Peekable, FromIterator, FusedIterator};
 use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds};
@@ -187,8 +187,8 @@
 }
 enum IntersectionInner<'a, T: 'a> {
     Stitch {
-        small_iter: Iter<'a, T>, // for size_hint, should be the smaller of the sets
-        other_iter: Iter<'a, T>,
+        a: Iter<'a, T>,
+        b: Iter<'a, T>,
     },
     Search {
         small_iter: Iter<'a, T>,
@@ -201,12 +201,12 @@
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match &self.inner {
             IntersectionInner::Stitch {
-                small_iter,
-                other_iter,
+                a,
+                b,
             } => f
                 .debug_tuple("Intersection")
-                .field(&small_iter)
-                .field(&other_iter)
+                .field(&a)
+                .field(&b)
                 .finish(),
             IntersectionInner::Search {
                 small_iter,
@@ -397,8 +397,8 @@
             // Iterate both sets jointly, spotting matches along the way.
             Intersection {
                 inner: IntersectionInner::Stitch {
-                    small_iter: small.iter(),
-                    other_iter: other.iter(),
+                    a: small.iter(),
+                    b: other.iter(),
                 },
             }
         } else {
@@ -1221,11 +1221,11 @@
         Intersection {
             inner: match &self.inner {
                 IntersectionInner::Stitch {
-                    small_iter,
-                    other_iter,
+                    a,
+                    b,
                 } => IntersectionInner::Stitch {
-                    small_iter: small_iter.clone(),
-                    other_iter: other_iter.clone(),
+                    a: a.clone(),
+                    b: b.clone(),
                 },
                 IntersectionInner::Search {
                     small_iter,
@@ -1245,16 +1245,16 @@
     fn next(&mut self) -> Option<&'a T> {
         match &mut self.inner {
             IntersectionInner::Stitch {
-                small_iter,
-                other_iter,
+                a,
+                b,
             } => {
-                let mut small_next = small_iter.next()?;
-                let mut other_next = other_iter.next()?;
+                let mut a_next = a.next()?;
+                let mut b_next = b.next()?;
                 loop {
-                    match Ord::cmp(small_next, other_next) {
-                        Less => small_next = small_iter.next()?,
-                        Greater => other_next = other_iter.next()?,
-                        Equal => return Some(small_next),
+                    match Ord::cmp(a_next, b_next) {
+                        Less => a_next = a.next()?,
+                        Greater => b_next = b.next()?,
+                        Equal => return Some(a_next),
                     }
                 }
             }
@@ -1272,7 +1272,7 @@
 
     fn size_hint(&self) -> (usize, Option<usize>) {
         let min_len = match &self.inner {
-            IntersectionInner::Stitch { small_iter, .. } => small_iter.len(),
+            IntersectionInner::Stitch { a, b } => min(a.len(), b.len()),
             IntersectionInner::Search { small_iter, .. } => small_iter.len(),
         };
         (0, Some(min_len))
diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs
index 9a6c57d..ecb5948 100644
--- a/src/liballoc/collections/linked_list/tests.rs
+++ b/src/liballoc/collections/linked_list/tests.rs
@@ -102,8 +102,8 @@
         assert_eq!(m.pop_front(), Some(elt))
     }
     assert_eq!(n.len(), 0);
-    // let's make sure it's working properly, since we
-    // did some direct changes to private members
+    // Let's make sure it's working properly, since we
+    // did some direct changes to private members.
     n.push_back(3);
     assert_eq!(n.len(), 1);
     assert_eq!(n.pop_front(), Some(3));
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 4a48945..9e6ed92 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -117,7 +117,7 @@
 #![feature(allocator_internals)]
 #![feature(on_unimplemented)]
 #![feature(rustc_const_unstable)]
-#![feature(const_vec_new)]
+#![cfg_attr(bootstrap, feature(const_vec_new))]
 #![feature(slice_partition_dedup)]
 #![feature(maybe_uninit_extra, maybe_uninit_slice)]
 #![feature(alloc_layout_extra)]
@@ -171,3 +171,9 @@
 mod std {
     pub use core::ops; // RangeFull
 }
+
+#[doc(hidden)]
+#[unstable(feature = "liballoc_internals", issue = "0", reason = "implementation detail")]
+pub mod __export {
+    pub use core::format_args;
+}
diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs
index 0b5e186d..2f2cdc3 100644
--- a/src/liballoc/macros.rs
+++ b/src/liballoc/macros.rs
@@ -98,5 +98,5 @@
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 macro_rules! format {
-    ($($arg:tt)*) => ($crate::fmt::format(::core::format_args!($($arg)*)))
+    ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
 }
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index bc8a38f..ee75fc2 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -19,26 +19,26 @@
 /// involved. This type is excellent for building your own data structures like Vec and VecDeque.
 /// In particular:
 ///
-/// * Produces Unique::empty() on zero-sized types
-/// * Produces Unique::empty() on zero-length allocations
-/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics)
-/// * Guards against 32-bit systems allocating more than isize::MAX bytes
-/// * Guards against overflowing your length
-/// * Aborts on OOM or calls handle_alloc_error as applicable
-/// * Avoids freeing Unique::empty()
-/// * Contains a ptr::Unique and thus endows the user with all related benefits
+/// * Produces `Unique::empty()` on zero-sized types.
+/// * Produces `Unique::empty()` on zero-length allocations.
+/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics).
+/// * Guards against 32-bit systems allocating more than isize::MAX bytes.
+/// * Guards against overflowing your length.
+/// * Aborts on OOM or calls `handle_alloc_error` as applicable.
+/// * Avoids freeing `Unique::empty()`.
+/// * Contains a `ptr::Unique` and thus endows the user with all related benefits.
 ///
 /// This type does not in anyway inspect the memory that it manages. When dropped it *will*
-/// free its memory, but it *won't* try to Drop its contents. It is up to the user of RawVec
-/// to handle the actual things *stored* inside of a RawVec.
+/// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec`
+/// to handle the actual things *stored* inside of a `RawVec`.
 ///
-/// Note that a RawVec always forces its capacity to be usize::MAX for zero-sized types.
-/// This enables you to use capacity growing logic catch the overflows in your length
+/// Note that a `RawVec` always forces its capacity to be `usize::MAX` for zero-sized types.
+/// This enables you to use capacity-growing logic catch the overflows in your length
 /// that might occur with zero-sized types.
 ///
-/// However this means that you need to be careful when round-tripping this type
-/// with a `Box<[T]>`: `capacity()` won't yield the len. However `with_capacity`,
-/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity
+/// The above means that you need to be careful when round-tripping this type with a
+/// `Box<[T]>`, since `capacity()` won't yield the length. However, `with_capacity`,
+/// `shrink_to_fit`, and `from_box` will actually set `RawVec`'s private capacity
 /// field. This allows zero-sized types to not be special-cased by consumers of
 /// this type.
 #[allow(missing_debug_implementations)]
@@ -49,14 +49,14 @@
 }
 
 impl<T, A: Alloc> RawVec<T, A> {
-    /// Like `new` but parameterized over the choice of allocator for
-    /// the returned RawVec.
+    /// Like `new`, but parameterized over the choice of allocator for
+    /// the returned `RawVec`.
     pub const fn new_in(a: A) -> Self {
-        // !0 is usize::MAX. This branch should be stripped at compile time.
-        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`
+        // `!0` is `usize::MAX`. This branch should be stripped at compile time.
+        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`:
         //let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
 
-        // Unique::empty() doubles as "unallocated" and "zero-sized allocation"
+        // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation".
         RawVec {
             ptr: Unique::empty(),
             // FIXME(mark-i-m): use `cap` when ifs are allowed in const
@@ -65,15 +65,15 @@
         }
     }
 
-    /// Like `with_capacity` but parameterized over the choice of
-    /// allocator for the returned RawVec.
+    /// Like `with_capacity`, but parameterized over the choice of
+    /// allocator for the returned `RawVec`.
     #[inline]
     pub fn with_capacity_in(capacity: usize, a: A) -> Self {
         RawVec::allocate_in(capacity, false, a)
     }
 
-    /// Like `with_capacity_zeroed` but parameterized over the choice
-    /// of allocator for the returned RawVec.
+    /// Like `with_capacity_zeroed`, but parameterized over the choice
+    /// of allocator for the returned `RawVec`.
     #[inline]
     pub fn with_capacity_zeroed_in(capacity: usize, a: A) -> Self {
         RawVec::allocate_in(capacity, true, a)
@@ -86,7 +86,7 @@
             let alloc_size = capacity.checked_mul(elem_size).unwrap_or_else(|| capacity_overflow());
             alloc_guard(alloc_size).unwrap_or_else(|_| capacity_overflow());
 
-            // handles ZSTs and `capacity = 0` alike
+            // Handles ZSTs and `capacity == 0` alike.
             let ptr = if alloc_size == 0 {
                 NonNull::<T>::dangling()
             } else {
@@ -113,20 +113,45 @@
 }
 
 impl<T> RawVec<T, Global> {
-    /// Creates the biggest possible RawVec (on the system heap)
-    /// without allocating. If T has positive size, then this makes a
-    /// RawVec with capacity 0. If T has 0 size, then it makes a
-    /// RawVec with capacity `usize::MAX`. Useful for implementing
+    /// HACK(Centril): This exists because `#[unstable]` `const fn`s needn't conform
+    /// to `min_const_fn` and so they cannot be called in `min_const_fn`s either.
+    ///
+    /// If you change `RawVec<T>::new` or dependencies, please take care to not
+    /// introduce anything that would truly violate `min_const_fn`.
+    ///
+    /// NOTE: We could avoid this hack and check conformance with some
+    /// `#[rustc_force_min_const_fn]` attribute which requires conformance
+    /// with `min_const_fn` but does not necessarily allow calling it in
+    /// `stable(...) const fn` / user code not enabling `foo` when
+    /// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
+    pub const NEW: Self = Self::new();
+
+    /// Creates the biggest possible `RawVec` (on the system heap)
+    /// without allocating. If `T` has positive size, then this makes a
+    /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a
+    /// `RawVec` with capacity `usize::MAX`. Useful for implementing
     /// delayed allocation.
     pub const fn new() -> Self {
-        Self::new_in(Global)
+        // FIXME(Centril): Reintegrate this with `fn new_in` when we can.
+
+        // `!0` is `usize::MAX`. This branch should be stripped at compile time.
+        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`:
+        //let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
+
+        // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation".
+        RawVec {
+            ptr: Unique::empty(),
+            // FIXME(mark-i-m): use `cap` when ifs are allowed in const
+            cap: [0, !0][(mem::size_of::<T>() == 0) as usize],
+            a: Global,
+        }
     }
 
-    /// Creates a RawVec (on the system heap) with exactly the
+    /// Creates a `RawVec` (on the system heap) with exactly the
     /// capacity and alignment requirements for a `[T; capacity]`. This is
-    /// equivalent to calling RawVec::new when `capacity` is 0 or T is
+    /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is
     /// zero-sized. Note that if `T` is zero-sized this means you will
-    /// *not* get a RawVec with the requested capacity!
+    /// *not* get a `RawVec` with the requested capacity.
     ///
     /// # Panics
     ///
@@ -136,13 +161,13 @@
     ///
     /// # Aborts
     ///
-    /// Aborts on OOM
+    /// Aborts on OOM.
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
         RawVec::allocate_in(capacity, false, Global)
     }
 
-    /// Like `with_capacity` but guarantees the buffer is zeroed.
+    /// Like `with_capacity`, but guarantees the buffer is zeroed.
     #[inline]
     pub fn with_capacity_zeroed(capacity: usize) -> Self {
         RawVec::allocate_in(capacity, true, Global)
@@ -150,13 +175,13 @@
 }
 
 impl<T, A: Alloc> RawVec<T, A> {
-    /// Reconstitutes a RawVec from a pointer, capacity, and allocator.
+    /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
     ///
     /// # Undefined Behavior
     ///
-    /// The ptr must be allocated (via the given allocator `a`), and with the given capacity. The
-    /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems).
-    /// If the ptr and capacity come from a RawVec created via `a`, then this is guaranteed.
+    /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`.
+    /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems).
+    /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
     pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
         RawVec {
             ptr: Unique::new_unchecked(ptr),
@@ -167,13 +192,13 @@
 }
 
 impl<T> RawVec<T, Global> {
-    /// Reconstitutes a RawVec from a pointer, capacity.
+    /// Reconstitutes a `RawVec` from a pointer and capacity.
     ///
     /// # Undefined Behavior
     ///
-    /// The ptr must be allocated (on the system heap), and with the given capacity. The
-    /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems).
-    /// If the ptr and capacity come from a RawVec, then this is guaranteed.
+    /// The `ptr` must be allocated (on the system heap), and with the given `capacity`.
+    /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems).
+    /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed.
     pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self {
         RawVec {
             ptr: Unique::new_unchecked(ptr),
@@ -194,7 +219,7 @@
 
 impl<T, A: Alloc> RawVec<T, A> {
     /// Gets a raw pointer to the start of the allocation. Note that this is
-    /// Unique::empty() if `capacity = 0` or T is zero-sized. In the former case, you must
+    /// `Unique::empty()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
     /// be careful.
     pub fn ptr(&self) -> *mut T {
         self.ptr.as_ptr()
@@ -212,12 +237,12 @@
         }
     }
 
-    /// Returns a shared reference to the allocator backing this RawVec.
+    /// Returns a shared reference to the allocator backing this `RawVec`.
     pub fn alloc(&self) -> &A {
         &self.a
     }
 
-    /// Returns a mutable reference to the allocator backing this RawVec.
+    /// Returns a mutable reference to the allocator backing this `RawVec`.
     pub fn alloc_mut(&mut self) -> &mut A {
         &mut self.a
     }
@@ -247,7 +272,7 @@
     ///
     /// # Panics
     ///
-    /// * Panics if T is zero-sized on the assumption that you managed to exhaust
+    /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
     ///   all `usize::MAX` slots in your imaginary buffer.
     /// * Panics on 32-bit platforms if the requested capacity exceeds
     ///   `isize::MAX` bytes.
@@ -290,20 +315,20 @@
         unsafe {
             let elem_size = mem::size_of::<T>();
 
-            // since we set the capacity to usize::MAX when elem_size is
-            // 0, getting to here necessarily means the RawVec is overfull.
+            // Since we set the capacity to `usize::MAX` when `elem_size` is
+            // 0, getting to here necessarily means the `RawVec` is overfull.
             assert!(elem_size != 0, "capacity overflow");
 
             let (new_cap, uniq) = match self.current_layout() {
                 Some(cur) => {
                     // Since we guarantee that we never allocate more than
-                    // isize::MAX bytes, `elem_size * self.cap <= isize::MAX` as
+                    // `isize::MAX` bytes, `elem_size * self.cap <= isize::MAX` as
                     // a precondition, so this can't overflow. Additionally the
                     // alignment will never be too large as to "not be
                     // satisfiable", so `Layout::from_size_align` will always
                     // return `Some`.
                     //
-                    // tl;dr; we bypass runtime checks due to dynamic assertions
+                    // TL;DR, we bypass runtime checks due to dynamic assertions
                     // in this module, allowing us to use
                     // `from_size_align_unchecked`.
                     let new_cap = 2 * self.cap;
@@ -320,8 +345,8 @@
                     }
                 }
                 None => {
-                    // skip to 4 because tiny Vec's are dumb; but not if that
-                    // would cause overflow
+                    // Skip to 4 because tiny `Vec`'s are dumb; but not if that
+                    // would cause overflow.
                     let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
                     match self.a.alloc_array::<T>(new_cap) {
                         Ok(ptr) => (new_cap, ptr.into()),
@@ -342,7 +367,7 @@
     ///
     /// # Panics
     ///
-    /// * Panics if T is zero-sized on the assumption that you managed to exhaust
+    /// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
     ///   all `usize::MAX` slots in your imaginary buffer.
     /// * Panics on 32-bit platforms if the requested capacity exceeds
     ///   `isize::MAX` bytes.
@@ -356,15 +381,15 @@
                 None => return false, // nothing to double
             };
 
-            // since we set the capacity to usize::MAX when elem_size is
-            // 0, getting to here necessarily means the RawVec is overfull.
+            // Since we set the capacity to `usize::MAX` when `elem_size` is
+            // 0, getting to here necessarily means the `RawVec` is overfull.
             assert!(elem_size != 0, "capacity overflow");
 
-            // Since we guarantee that we never allocate more than isize::MAX
+            // Since we guarantee that we never allocate more than `isize::MAX`
             // bytes, `elem_size * self.cap <= isize::MAX` as a precondition, so
             // this can't overflow.
             //
-            // Similarly like with `double` above we can go straight to
+            // Similarly to with `double` above, we can go straight to
             // `Layout::from_size_align_unchecked` as we know this won't
             // overflow and the alignment is sufficiently small.
             let new_cap = 2 * self.cap;
@@ -409,7 +434,7 @@
     ///
     /// # Aborts
     ///
-    /// Aborts on OOM
+    /// Aborts on OOM.
     pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
         match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Exact) {
             Err(CapacityOverflow) => capacity_overflow(),
@@ -424,7 +449,7 @@
     fn amortized_new_size(&self, used_capacity: usize, needed_extra_capacity: usize)
         -> Result<usize, TryReserveError> {
 
-        // Nothing we can really do about these checks :(
+        // Nothing we can really do about these checks, sadly.
         let required_cap = used_capacity.checked_add(needed_extra_capacity)
             .ok_or(CapacityOverflow)?;
         // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
@@ -459,7 +484,7 @@
     ///
     /// # Aborts
     ///
-    /// Aborts on OOM
+    /// Aborts on OOM.
     ///
     /// # Examples
     ///
@@ -538,7 +563,7 @@
 
             // Here, `cap < used_capacity + needed_extra_capacity <= new_cap`
             // (regardless of whether `self.cap - used_capacity` wrapped).
-            // Therefore we can safely call grow_in_place.
+            // Therefore, we can safely call `grow_in_place`.
 
             let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0;
             // FIXME: may crash and burn on over-reserve
@@ -576,14 +601,14 @@
             return;
         }
 
-        // This check is my waterloo; it's the only thing Vec wouldn't have to do.
+        // This check is my waterloo; it's the only thing `Vec` wouldn't have to do.
         assert!(self.cap >= amount, "Tried to shrink to a larger capacity");
 
         if amount == 0 {
             // We want to create a new zero-length vector within the
-            // same allocator.  We use ptr::write to avoid an
+            // same allocator. We use `ptr::write` to avoid an
             // erroneous attempt to drop the contents, and we use
-            // ptr::read to sidestep condition against destructuring
+            // `ptr::read` to sidestep condition against destructuring
             // types that implement Drop.
 
             unsafe {
@@ -600,7 +625,7 @@
                 //
                 // We also know that `self.cap` is greater than `amount`, and
                 // consequently we don't need runtime checks for creating either
-                // layout
+                // layout.
                 let old_size = elem_size * self.cap;
                 let new_size = elem_size * amount;
                 let align = mem::align_of::<T>();
@@ -653,7 +678,7 @@
                 return Ok(());
             }
 
-            // Nothing we can really do about these checks :(
+            // Nothing we can really do about these checks, sadly.
             let new_cap = match strategy {
                 Exact => used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?,
                 Amortized => self.amortized_new_size(used_capacity, needed_extra_capacity)?,
@@ -692,7 +717,7 @@
     /// Converts the entire buffer into `Box<[T]>`.
     ///
     /// Note that this will correctly reconstitute any `cap` changes
-    /// that may have been performed. (see description of type for details)
+    /// that may have been performed. (See description of type for details.)
     ///
     /// # Undefined Behavior
     ///
@@ -700,7 +725,7 @@
     /// the rules around uninitialized boxed values are not finalized yet,
     /// but until they are, it is advisable to avoid them.
     pub unsafe fn into_box(self) -> Box<[T]> {
-        // NOTE: not calling `capacity()` here, actually using the real `cap` field!
+        // NOTE: not calling `capacity()` here; actually using the real `cap` field!
         let slice = slice::from_raw_parts_mut(self.ptr(), self.cap);
         let output: Box<[T]> = Box::from_raw(slice);
         mem::forget(self);
@@ -709,7 +734,7 @@
 }
 
 impl<T, A: Alloc> RawVec<T, A> {
-    /// Frees the memory owned by the RawVec *without* trying to Drop its contents.
+    /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
     pub unsafe fn dealloc_buffer(&mut self) {
         let elem_size = mem::size_of::<T>();
         if elem_size != 0 {
@@ -721,22 +746,20 @@
 }
 
 unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
-    /// Frees the memory owned by the RawVec *without* trying to Drop its contents.
+    /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
     fn drop(&mut self) {
         unsafe { self.dealloc_buffer(); }
     }
 }
 
-
-
 // We need to guarantee the following:
-// * We don't ever allocate `> isize::MAX` byte-size objects
-// * We don't overflow `usize::MAX` and actually allocate too little
+// * We don't ever allocate `> isize::MAX` byte-size objects.
+// * We don't overflow `usize::MAX` and actually allocate too little.
 //
 // On 64-bit we just need to check for overflow since trying to allocate
 // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add
 // an extra guard for this in case we're running on a platform which can use
-// all 4GB in user-space. e.g., PAE or x32
+// all 4GB in user-space, e.g., PAE or x32.
 
 #[inline]
 fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
@@ -751,5 +774,5 @@
 // ensure that the code generation related to these panics is minimal as there's
 // only one location which panics rather than a bunch throughout the module.
 fn capacity_overflow() -> ! {
-    panic!("capacity overflow")
+    panic!("capacity overflow");
 }
diff --git a/src/liballoc/raw_vec/tests.rs b/src/liballoc/raw_vec/tests.rs
index c389898..d35b62f 100644
--- a/src/liballoc/raw_vec/tests.rs
+++ b/src/liballoc/raw_vec/tests.rs
@@ -5,12 +5,12 @@
     use crate::alloc::AllocErr;
 
     // Writing a test of integration between third-party
-    // allocators and RawVec is a little tricky because the RawVec
+    // allocators and `RawVec` is a little tricky because the `RawVec`
     // API does not expose fallible allocation methods, so we
     // cannot check what happens when allocator is exhausted
     // (beyond detecting a panic).
     //
-    // Instead, this just checks that the RawVec methods do at
+    // Instead, this just checks that the `RawVec` methods do at
     // least go through the Allocator API when it reserves
     // storage.
 
@@ -44,7 +44,7 @@
 fn reserve_does_not_overallocate() {
     {
         let mut v: RawVec<u32> = RawVec::new();
-        // First `reserve` allocates like `reserve_exact`
+        // First, `reserve` allocates like `reserve_exact`.
         v.reserve(0, 9);
         assert_eq!(9, v.capacity());
     }
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 2b222ca..f234ac5 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -567,7 +567,7 @@
     ///     let x = Rc::from_raw(x_ptr);
     ///     assert_eq!(&*x, "hello");
     ///
-    ///     // Further calls to `Rc::from_raw(x_ptr)` would be memory unsafe.
+    ///     // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe.
     /// }
     ///
     /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
@@ -1832,8 +1832,9 @@
         }
     }
 
-    /// Returns `true` if the two `Weak`s point to the same value (not just values
-    /// that compare as equal).
+    /// Returns `true` if the two `Weak`s point to the same value (not just
+    /// values that compare as equal), or if both don't point to any value
+    /// (because they were created with `Weak::new()`).
     ///
     /// # Notes
     ///
@@ -1843,7 +1844,6 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::rc::Rc;
     ///
     /// let first_rc = Rc::new(5);
@@ -1861,7 +1861,6 @@
     /// Comparing `Weak::new`.
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::rc::{Rc, Weak};
     ///
     /// let first = Weak::new();
@@ -1873,7 +1872,7 @@
     /// assert!(!first.ptr_eq(&third));
     /// ```
     #[inline]
-    #[unstable(feature = "weak_ptr_eq", issue = "55981")]
+    #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
         self.ptr.as_ptr() == other.ptr.as_ptr()
     }
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index b65f191..1166e7b 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -369,7 +369,7 @@
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_string_new")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_string_new"))]
     pub const fn new() -> String {
         String { vec: Vec::new() }
     }
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 9ffc167..45f9816 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -547,7 +547,7 @@
     ///     let x = Arc::from_raw(x_ptr);
     ///     assert_eq!(&*x, "hello");
     ///
-    ///     // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe.
+    ///     // Further calls to `Arc::from_raw(x_ptr)` would be memory-unsafe.
     /// }
     ///
     /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
@@ -1550,19 +1550,18 @@
         }
     }
 
-    /// Returns `true` if the two `Weak`s point to the same value (not just values
-    /// that compare as equal).
+    /// Returns `true` if the two `Weak`s point to the same value (not just
+    /// values that compare as equal), or if both don't point to any value
+    /// (because they were created with `Weak::new()`).
     ///
     /// # Notes
     ///
     /// Since this compares pointers it means that `Weak::new()` will equal each
     /// other, even though they don't point to any value.
     ///
-    ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::sync::Arc;
     ///
     /// let first_rc = Arc::new(5);
@@ -1580,7 +1579,6 @@
     /// Comparing `Weak::new`.
     ///
     /// ```
-    /// #![feature(weak_ptr_eq)]
     /// use std::sync::{Arc, Weak};
     ///
     /// let first = Weak::new();
@@ -1592,7 +1590,7 @@
     /// assert!(!first.ptr_eq(&third));
     /// ```
     #[inline]
-    #[unstable(feature = "weak_ptr_eq", issue = "55981")]
+    #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
         self.ptr.as_ptr() == other.ptr.as_ptr()
     }
diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs
index 62ccb53..35db18c 100644
--- a/src/liballoc/tests/btree/set.rs
+++ b/src/liballoc/tests/btree/set.rs
@@ -91,6 +91,17 @@
 }
 
 #[test]
+fn test_intersection_size_hint() {
+    let x: BTreeSet<i32> = [3, 4].iter().copied().collect();
+    let y: BTreeSet<i32> = [1, 2, 3].iter().copied().collect();
+    let mut iter = x.intersection(&y);
+    assert_eq!(iter.size_hint(), (0, Some(2)));
+    assert_eq!(iter.next(), Some(&3));
+    assert_eq!(iter.size_hint(), (0, Some(0)));
+    assert_eq!(iter.next(), None);
+}
+
+#[test]
 fn test_difference() {
     fn check_difference(a: &[i32], b: &[i32], expected: &[i32]) {
         check(a, b, expected, |x, y, f| x.difference(y).all(f))
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index d5dc2d4..405969a 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -314,10 +314,10 @@
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_vec_new")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_vec_new"))]
     pub const fn new() -> Vec<T> {
         Vec {
-            buf: RawVec::new(),
+            buf: RawVec::NEW,
             len: 0,
         }
     }
@@ -685,21 +685,25 @@
     /// [`drain`]: #method.drain
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn truncate(&mut self, len: usize) {
-        let current_len = self.len;
-        unsafe {
-            let mut ptr = self.as_mut_ptr().add(self.len);
-            // Set the final length at the end, keeping in mind that
-            // dropping an element might panic. Works around a missed
-            // optimization, as seen in the following issue:
-            // https://github.com/rust-lang/rust/issues/51802
-            let mut local_len = SetLenOnDrop::new(&mut self.len);
+        if mem::needs_drop::<T>() {
+            let current_len = self.len;
+            unsafe {
+                let mut ptr = self.as_mut_ptr().add(self.len);
+                // Set the final length at the end, keeping in mind that
+                // dropping an element might panic. Works around a missed
+                // optimization, as seen in the following issue:
+                // https://github.com/rust-lang/rust/issues/51802
+                let mut local_len = SetLenOnDrop::new(&mut self.len);
 
-            // drop any extra elements
-            for _ in len..current_len {
-                local_len.decrement_len(1);
-                ptr = ptr.offset(-1);
-                ptr::drop_in_place(ptr);
+                // drop any extra elements
+                for _ in len..current_len {
+                    local_len.decrement_len(1);
+                    ptr = ptr.offset(-1);
+                    ptr::drop_in_place(ptr);
+                }
             }
+        } else if len <= self.len {
+            self.len = len;
         }
     }
 
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index e8a0a88..0afbf4f 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -153,13 +153,13 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn is<T: Any>(&self) -> bool {
-        // Get TypeId of the type this function is instantiated with
+        // Get `TypeId` of the type this function is instantiated with.
         let t = TypeId::of::<T>();
 
-        // Get TypeId of the type in the trait object
+        // Get `TypeId` of the type in the trait object.
         let concrete = self.type_id();
 
-        // Compare both TypeIds on equality
+        // Compare both `TypeId`s on equality.
         t == concrete
     }
 
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
index 402a7b2..06f2b7b 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert.rs
@@ -42,11 +42,11 @@
 
 use crate::fmt;
 
-/// An identity function.
+/// The identity function.
 ///
 /// Two things are important to note about this function:
 ///
-/// - It is not always equivalent to a closure like `|x| x` since the
+/// - It is not always equivalent to a closure like `|x| x`, since the
 ///   closure may coerce `x` into a different type.
 ///
 /// - It moves the input `x` passed to the function.
@@ -56,31 +56,32 @@
 ///
 /// # Examples
 ///
-/// Using `identity` to do nothing among other interesting functions:
+/// Using `identity` to do nothing in a sequence of other, interesting,
+/// functions:
 ///
 /// ```rust
 /// use std::convert::identity;
 ///
 /// fn manipulation(x: u32) -> u32 {
-///     // Let's assume that this function does something interesting.
+///     // Let's pretend that adding one is an interesting function.
 ///     x + 1
 /// }
 ///
 /// let _arr = &[identity, manipulation];
 /// ```
 ///
-/// Using `identity` to get a function that changes nothing in a conditional:
+/// Using `identity` as a "do nothing" base case in a conditional:
 ///
 /// ```rust
 /// use std::convert::identity;
 ///
 /// # let condition = true;
-///
+/// #
 /// # fn manipulation(x: u32) -> u32 { x + 1 }
-///
+/// #
 /// let do_stuff = if condition { manipulation } else { identity };
 ///
-/// // do more interesting stuff..
+/// // Do more interesting stuff...
 ///
 /// let _results = do_stuff(42);
 /// ```
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index 8e1ac60..3b8edc2 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -5,7 +5,7 @@
 use crate::intrinsics;
 
 use super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen};
-use super::LoopState;
+use super::{LoopState, from_fn};
 
 mod chain;
 mod flatten;
@@ -534,6 +534,26 @@
             self.iter.nth(nth - 1);
         }
     }
+
+    fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
+    where
+        F: FnMut(Acc, Self::Item) -> R,
+        R: Try<Ok = Acc>,
+    {
+        #[inline]
+        fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
+            move || iter.nth(step)
+        }
+
+        if self.first_take {
+            self.first_take = false;
+            match self.iter.next() {
+                None => return Try::from_ok(acc),
+                Some(x) => acc = f(acc, x)?,
+            }
+        }
+        from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f)
+    }
 }
 
 impl<I> StepBy<I> where I: ExactSizeIterator {
@@ -567,6 +587,28 @@
             .saturating_add(self.next_back_index());
         self.iter.nth_back(n)
     }
+
+    fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
+    where
+        F: FnMut(Acc, Self::Item) -> R,
+        R: Try<Ok = Acc>,
+    {
+        #[inline]
+        fn nth_back<I: DoubleEndedIterator>(
+            iter: &mut I,
+            step: usize,
+        ) -> impl FnMut() -> Option<I::Item> + '_ {
+            move || iter.nth_back(step)
+        }
+
+        match self.next_back() {
+            None => Try::from_ok(init),
+            Some(x) => {
+                let acc = f(init, x)?;
+                from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f)
+            }
+        }
+    }
 }
 
 // StepBy can only make the iterator shorter, so the len will still fit.
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index 8fd5fe0..c09df3f 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -2557,11 +2557,41 @@
     /// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn cmp<I>(mut self, other: I) -> Ordering where
+    fn cmp<I>(self, other: I) -> Ordering
+    where
         I: IntoIterator<Item = Self::Item>,
         Self::Item: Ord,
         Self: Sized,
     {
+        self.cmp_by(other, |x, y| x.cmp(&y))
+    }
+
+    /// Lexicographically compares the elements of this `Iterator` with those
+    /// of another with respect to the specified comparison function.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_order_by)]
+    ///
+    /// use std::cmp::Ordering;
+    ///
+    /// let xs = [1, 2, 3, 4];
+    /// let ys = [1, 4, 9, 16];
+    ///
+    /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| x.cmp(&y)), Ordering::Less);
+    /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal);
+    /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
+    /// ```
+    #[unstable(feature = "iter_order_by", issue = "0")]
+    fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
+    where
+        Self: Sized,
+        I: IntoIterator,
+        F: FnMut(Self::Item, I::Item) -> Ordering,
+    {
         let mut other = other.into_iter();
 
         loop {
@@ -2579,7 +2609,7 @@
                 Some(val) => val,
             };
 
-            match x.cmp(&y) {
+            match cmp(x, y) {
                 Ordering::Equal => (),
                 non_eq => return non_eq,
             }
@@ -2601,11 +2631,50 @@
     /// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn partial_cmp<I>(mut self, other: I) -> Option<Ordering> where
+    fn partial_cmp<I>(self, other: I) -> Option<Ordering>
+    where
         I: IntoIterator,
         Self::Item: PartialOrd<I::Item>,
         Self: Sized,
     {
+        self.partial_cmp_by(other, |x, y| x.partial_cmp(&y))
+    }
+
+    /// Lexicographically compares the elements of this `Iterator` with those
+    /// of another with respect to the specified comparison function.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_order_by)]
+    ///
+    /// use std::cmp::Ordering;
+    ///
+    /// let xs = [1.0, 2.0, 3.0, 4.0];
+    /// let ys = [1.0, 4.0, 9.0, 16.0];
+    ///
+    /// assert_eq!(
+    ///     xs.iter().partial_cmp_by(&ys, |&x, &y| x.partial_cmp(&y)),
+    ///     Some(Ordering::Less)
+    /// );
+    /// assert_eq!(
+    ///     xs.iter().partial_cmp_by(&ys, |&x, &y| (x * x).partial_cmp(&y)),
+    ///     Some(Ordering::Equal)
+    /// );
+    /// assert_eq!(
+    ///     xs.iter().partial_cmp_by(&ys, |&x, &y| (2.0 * x).partial_cmp(&y)),
+    ///     Some(Ordering::Greater)
+    /// );
+    /// ```
+    #[unstable(feature = "iter_order_by", issue = "0")]
+    fn partial_cmp_by<I, F>(mut self, other: I, mut partial_cmp: F) -> Option<Ordering>
+    where
+        Self: Sized,
+        I: IntoIterator,
+        F: FnMut(Self::Item, I::Item) -> Option<Ordering>,
+    {
         let mut other = other.into_iter();
 
         loop {
@@ -2623,7 +2692,7 @@
                 Some(val) => val,
             };
 
-            match x.partial_cmp(&y) {
+            match partial_cmp(x, y) {
                 Some(Ordering::Equal) => (),
                 non_eq => return non_eq,
             }
@@ -2640,11 +2709,37 @@
     /// assert_eq!([1].iter().eq([1, 2].iter()), false);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
-    fn eq<I>(mut self, other: I) -> bool where
+    fn eq<I>(self, other: I) -> bool
+    where
         I: IntoIterator,
         Self::Item: PartialEq<I::Item>,
         Self: Sized,
     {
+        self.eq_by(other, |x, y| x == y)
+    }
+
+    /// Determines if the elements of this `Iterator` are equal to those of
+    /// another with respect to the specified equality function.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_order_by)]
+    ///
+    /// let xs = [1, 2, 3, 4];
+    /// let ys = [1, 4, 9, 16];
+    ///
+    /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
+    /// ```
+    #[unstable(feature = "iter_order_by", issue = "0")]
+    fn eq_by<I, F>(mut self, other: I, mut eq: F) -> bool
+    where
+        Self: Sized,
+        I: IntoIterator,
+        F: FnMut(Self::Item, I::Item) -> bool,
+    {
         let mut other = other.into_iter();
 
         loop {
@@ -2658,7 +2753,9 @@
                 Some(val) => val,
             };
 
-            if x != y { return false }
+            if !eq(x, y) {
+                return false;
+            }
         }
     }
 
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 690cff4..a2cc585 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -87,7 +87,7 @@
 #![feature(link_llvm_intrinsics)]
 #![feature(never_type)]
 #![feature(nll)]
-#![feature(bind_by_move_pattern_guards)]
+#![cfg_attr(boostrap_stdarch_ignore_this, feature(bind_by_move_pattern_guards))]
 #![feature(exhaustive_patterns)]
 #![feature(no_core)]
 #![feature(on_unimplemented)]
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 89af252..347e7dc 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -602,10 +602,10 @@
 unsafe impl<T: ?Sized> Freeze for &T {}
 unsafe impl<T: ?Sized> Freeze for &mut T {}
 
-/// Types which can be safely moved after being pinned.
+/// Types that can be safely moved after being pinned.
 ///
 /// Since Rust itself has no notion of immovable types, and considers moves
-/// (e.g. through assignment or [`mem::replace`]) to always be safe,
+/// (e.g., through assignment or [`mem::replace`]) to always be safe,
 /// this trait cannot prevent types from moving by itself.
 ///
 /// Instead it is used to prevent moves through the type system,
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index b46e06f..df1c00c 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -1401,12 +1401,8 @@
 ```"),
             #[stable(feature = "no_panic_abs", since = "1.13.0")]
             #[inline]
-            pub fn wrapping_abs(self) -> Self {
-                if self.is_negative() {
-                    self.wrapping_neg()
-                } else {
-                    self
-                }
+            pub const fn wrapping_abs(self) -> Self {
+                (self ^ (self >> ($BITS - 1))).wrapping_sub(self >> ($BITS - 1))
             }
         }
 
@@ -1764,12 +1760,8 @@
 ```"),
             #[stable(feature = "no_panic_abs", since = "1.13.0")]
             #[inline]
-            pub fn overflowing_abs(self) -> (Self, bool) {
-                if self.is_negative() {
-                    self.overflowing_neg()
-                } else {
-                    (self, false)
-                }
+            pub const fn overflowing_abs(self) -> (Self, bool) {
+                (self ^ (self >> ($BITS - 1))).overflowing_sub(self >> ($BITS - 1))
             }
         }
 
@@ -1973,15 +1965,11 @@
             #[stable(feature = "rust1", since = "1.0.0")]
             #[inline]
             #[rustc_inherit_overflow_checks]
-            pub fn abs(self) -> Self {
-                if self.is_negative() {
-                    // Note that the #[inline] above means that the overflow
-                    // semantics of this negation depend on the crate we're being
-                    // inlined into.
-                    -self
-                } else {
-                    self
-                }
+            pub const fn abs(self) -> Self {
+                // Note that the #[inline] above means that the overflow
+                // semantics of the subtraction depend on the crate we're being
+                // inlined into.
+                (self ^ (self >> ($BITS - 1))) - (self >> ($BITS - 1))
             }
         }
 
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 79bd04b..5569d99 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -295,7 +295,7 @@
     /// [`Pin`]: ../pin/struct.Pin.html
     #[inline]
     #[stable(feature = "pin", since = "1.33.0")]
-    pub fn as_pin_ref<'a>(self: Pin<&'a Option<T>>) -> Option<Pin<&'a T>> {
+    pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
         unsafe {
             Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x))
         }
@@ -306,7 +306,7 @@
     /// [`Pin`]: ../pin/struct.Pin.html
     #[inline]
     #[stable(feature = "pin", since = "1.33.0")]
-    pub fn as_pin_mut<'a>(self: Pin<&'a mut Option<T>>) -> Option<Pin<&'a mut T>> {
+    pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
         unsafe {
             Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x))
         }
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 1080fd3..be59e83 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -233,7 +233,7 @@
 //! # type Field = i32;
 //! # struct Struct { field: Field }
 //! impl Struct {
-//!     fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> &'a mut Field {
+//!     fn pin_get_field(self: Pin<&mut Self>) -> &mut Field {
 //!         // This is okay because `field` is never considered pinned.
 //!         unsafe { &mut self.get_unchecked_mut().field }
 //!     }
@@ -257,7 +257,7 @@
 //! # type Field = i32;
 //! # struct Struct { field: Field }
 //! impl Struct {
-//!     fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut Field> {
+//!     fn pin_get_field(self: Pin<&mut Self>) -> Pin<&mut Field> {
 //!         // This is okay because `field` is pinned when `self` is.
 //!         unsafe { self.map_unchecked_mut(|s| &mut s.field) }
 //!     }
@@ -549,7 +549,7 @@
     /// ruled out by the contract of `Pin::new_unchecked`.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn as_ref(self: &Pin<P>) -> Pin<&P::Target> {
+    pub fn as_ref(&self) -> Pin<&P::Target> {
         unsafe { Pin::new_unchecked(&*self.pointer) }
     }
 
@@ -586,7 +586,7 @@
     /// ruled out by the contract of `Pin::new_unchecked`.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn as_mut(self: &mut Pin<P>) -> Pin<&mut P::Target> {
+    pub fn as_mut(&mut self) -> Pin<&mut P::Target> {
         unsafe { Pin::new_unchecked(&mut *self.pointer) }
     }
 
@@ -596,7 +596,7 @@
     /// run before being overwritten, so no pinning guarantee is violated.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn set(self: &mut Pin<P>, value: P::Target)
+    pub fn set(&mut self, value: P::Target)
     where
         P::Target: Sized,
     {
@@ -621,7 +621,7 @@
     ///
     /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning
     #[stable(feature = "pin", since = "1.33.0")]
-    pub unsafe fn map_unchecked<U, F>(self: Pin<&'a T>, func: F) -> Pin<&'a U> where
+    pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U> where
         F: FnOnce(&T) -> &U,
     {
         let pointer = &*self.pointer;
@@ -648,7 +648,7 @@
     /// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn get_ref(self: Pin<&'a T>) -> &'a T {
+    pub fn get_ref(self) -> &'a T {
         self.pointer
     }
 }
@@ -657,7 +657,7 @@
     /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> {
+    pub fn into_ref(self) -> Pin<&'a T> {
         Pin { pointer: self.pointer }
     }
 
@@ -672,7 +672,7 @@
     /// with the same lifetime as the original `Pin`.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T
+    pub fn get_mut(self) -> &'a mut T
         where T: Unpin,
     {
         self.pointer
@@ -690,7 +690,7 @@
     /// instead.
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T {
+    pub unsafe fn get_unchecked_mut(self) -> &'a mut T {
         self.pointer
     }
 
@@ -710,7 +710,7 @@
     ///
     /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning
     #[stable(feature = "pin", since = "1.33.0")]
-    pub unsafe fn map_unchecked_mut<U, F>(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
+    pub unsafe fn map_unchecked_mut<U, F>(self, func: F) -> Pin<&'a mut U> where
         F: FnOnce(&mut T) -> &mut U,
     {
         let pointer = Pin::get_unchecked_mut(self);
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index f5fbd1a..13ccc9b 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -1042,7 +1042,7 @@
         (self as *const u8) == null()
     }
 
-    /// Cast to a pointer to a different type
+    /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
     #[inline]
     pub const fn cast<U>(self) -> *const U {
@@ -1726,7 +1726,7 @@
         (self as *mut u8) == null_mut()
     }
 
-    /// Cast to a pointer to a different type
+    /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
     #[inline]
     pub const fn cast<U>(self) -> *mut U {
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index ad3d1ce..7dcd57f 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -125,7 +125,7 @@
         &mut *self.as_ptr()
     }
 
-    /// Cast to a pointer of another type
+    /// Casts to a pointer of another type.
     #[stable(feature = "nonnull_cast", since = "1.27.0")]
     #[inline]
     pub const fn cast<U>(self) -> NonNull<U> {
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 8dfb19f..a731115 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -979,9 +979,8 @@
     /// let some_ptr  = AtomicPtr::new(ptr);
     ///
     /// let other_ptr   = &mut 10;
-    /// let another_ptr = &mut 10;
     ///
-    /// let value = some_ptr.compare_and_swap(other_ptr, another_ptr, Ordering::Relaxed);
+    /// let value = some_ptr.compare_and_swap(ptr, other_ptr, Ordering::Relaxed);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1021,9 +1020,8 @@
     /// let some_ptr  = AtomicPtr::new(ptr);
     ///
     /// let other_ptr   = &mut 10;
-    /// let another_ptr = &mut 10;
     ///
-    /// let value = some_ptr.compare_exchange(other_ptr, another_ptr,
+    /// let value = some_ptr.compare_exchange(ptr, other_ptr,
     ///                                       Ordering::SeqCst, Ordering::Relaxed);
     /// ```
     #[inline]
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index 8e0658d..c9096b7 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -58,6 +58,62 @@
 }
 
 #[test]
+fn test_cmp_by() {
+    use core::cmp::Ordering;
+
+    let f = |x: i32, y: i32| (x * x).cmp(&y);
+    let xs = || [1, 2, 3, 4].iter().copied();
+    let ys = || [1, 4, 16].iter().copied();
+
+    assert_eq!(xs().cmp_by(ys(), f), Ordering::Less);
+    assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater);
+    assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal);
+    assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater);
+    assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less);
+    assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater);
+}
+
+#[test]
+fn test_partial_cmp_by() {
+    use core::cmp::Ordering;
+    use core::f64;
+
+    let f = |x: i32, y: i32| (x * x).partial_cmp(&y);
+    let xs = || [1, 2, 3, 4].iter().copied();
+    let ys = || [1, 4, 16].iter().copied();
+
+    assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less));
+    assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
+    assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal));
+    assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater));
+    assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less));
+    assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater));
+
+    let f = |x: f64, y: f64| (x * x).partial_cmp(&y);
+    let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied();
+    let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied();
+
+    assert_eq!(xs().partial_cmp_by(ys(), f), None);
+    assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
+}
+
+#[test]
+fn test_eq_by() {
+    let f = |x: i32, y: i32| x * x == y;
+    let xs = || [1, 2, 3, 4].iter().copied();
+    let ys = || [1, 4, 9, 16].iter().copied();
+
+    assert!(xs().eq_by(ys(), f));
+    assert!(!ys().eq_by(xs(), f));
+    assert!(!xs().eq_by(xs(), f));
+    assert!(!ys().eq_by(ys(), f));
+
+    assert!(!xs().take(3).eq_by(ys(), f));
+    assert!(!xs().eq_by(ys().take(3), f));
+    assert!(xs().take(3).eq_by(ys().take(3), f));
+}
+
+#[test]
 fn test_counter_from_iter() {
     let it = (0..).step_by(5).take(10);
     let xs: Vec<isize> = FromIterator::from_iter(it);
@@ -330,6 +386,23 @@
 }
 
 #[test]
+fn test_iterator_step_by_nth_try_fold() {
+    let mut it = (0..).step_by(10);
+    assert_eq!(it.try_fold(0, i8::checked_add), None);
+    assert_eq!(it.next(), Some(60));
+    assert_eq!(it.try_fold(0, i8::checked_add), None);
+    assert_eq!(it.next(), Some(90));
+
+    let mut it = (100..).step_by(10);
+    assert_eq!(it.try_fold(50, i8::checked_add), None);
+    assert_eq!(it.next(), Some(110));
+
+    let mut it = (100..=100).step_by(10);
+    assert_eq!(it.next(), Some(100));
+    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+}
+
+#[test]
 fn test_iterator_step_by_nth_back() {
     let mut it = (0..16).step_by(5);
     assert_eq!(it.nth_back(0), Some(15));
@@ -355,6 +428,24 @@
 }
 
 #[test]
+fn test_iterator_step_by_nth_try_rfold() {
+    let mut it = (0..100).step_by(10);
+    assert_eq!(it.try_rfold(0, i8::checked_add), None);
+    assert_eq!(it.next_back(), Some(70));
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.try_rfold(0, i8::checked_add), None);
+    assert_eq!(it.next_back(), Some(30));
+
+    let mut it = (0..100).step_by(10);
+    assert_eq!(it.try_rfold(50, i8::checked_add), None);
+    assert_eq!(it.next_back(), Some(80));
+
+    let mut it = (100..=100).step_by(10);
+    assert_eq!(it.next_back(), Some(100));
+    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+}
+
+#[test]
 #[should_panic]
 fn test_iterator_step_by_zero() {
     let mut it = (0..).step_by(0);
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index b2c29aa..050195c 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -33,6 +33,7 @@
 #![feature(const_fn)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_is_partitioned)]
+#![feature(iter_order_by)]
 
 extern crate test;
 
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index a479fab..0834faf 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -15,7 +15,6 @@
 fmt_macros = { path = "../libfmt_macros" }
 graphviz = { path = "../libgraphviz" }
 jobserver = "0.1"
-lazy_static = "1.0.0"
 num_cpus = "1.0"
 scoped-tls = "1.0"
 log = { version = "0.4", features = ["release_max_level_info", "std"] }
@@ -31,8 +30,8 @@
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 backtrace = "0.3.3"
-parking_lot = "0.7"
-byteorder = { version = "1.1", features = ["i128"]}
+parking_lot = "0.9"
+byteorder = { version = "1.3" }
 chalk-engine = { version = "0.9.0", default-features=false }
 rustc_fs_util = { path = "../librustc_fs_util" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index b50cfa0..58789a1 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1316,7 +1316,7 @@
                             ImplTraitContext::Universal(in_band_ty_params),
                         );
                         // Set the name to `impl Bound1 + Bound2`.
-                        let ident = Ident::from_str(&pprust::ty_to_string(t)).with_span_pos(span);
+                        let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
                         in_band_ty_params.push(hir::GenericParam {
                             hir_id: self.lower_node_id(def_node_id),
                             name: ParamName::Plain(ident),
diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index 0d8986d..a46cdab 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -507,14 +507,13 @@
 
     /// Desugar `<expr>.await` into:
     /// ```rust
-    /// {
-    ///     let mut pinned = <expr>;
-    ///     loop {
+    /// match <expr> {
+    ///     mut pinned => loop {
     ///         match ::std::future::poll_with_tls_context(unsafe {
-    ///             ::std::pin::Pin::new_unchecked(&mut pinned)
+    ///             <::std::pin::Pin>::new_unchecked(&mut pinned)
     ///         }) {
     ///             ::std::task::Poll::Ready(result) => break result,
-    ///             ::std::task::Poll::Pending => {},
+    ///             ::std::task::Poll::Pending => {}
     ///         }
     ///         yield ();
     ///     }
@@ -549,21 +548,12 @@
             self.allow_gen_future.clone(),
         );
 
-        // let mut pinned = <expr>;
-        let expr = P(self.lower_expr(expr));
         let pinned_ident = Ident::with_dummy_span(sym::pinned);
         let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
             span,
             pinned_ident,
             hir::BindingAnnotation::Mutable,
         );
-        let pinned_let = self.stmt_let_pat(
-            ThinVec::new(),
-            span,
-            Some(expr),
-            pinned_pat,
-            hir::LocalSource::AwaitDesugar,
-        );
 
         // ::std::future::poll_with_tls_context(unsafe {
         //     ::std::pin::Pin::new_unchecked(&mut pinned)
@@ -621,7 +611,7 @@
             self.arm(hir_vec![pending_pat], empty_block)
         };
 
-        let match_stmt = {
+        let inner_match_stmt = {
             let match_expr = self.expr_match(
                 span,
                 poll_expr,
@@ -643,10 +633,11 @@
 
         let loop_block = P(self.block_all(
             span,
-            hir_vec![match_stmt, yield_stmt],
+            hir_vec![inner_match_stmt, yield_stmt],
             None,
         ));
 
+        // loop { .. }
         let loop_expr = P(hir::Expr {
             hir_id: loop_hir_id,
             node: hir::ExprKind::Loop(
@@ -658,10 +649,14 @@
             attrs: ThinVec::new(),
         });
 
-        hir::ExprKind::Block(
-            P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))),
-            None,
-        )
+        // mut pinned => loop { ... }
+        let pinned_arm = self.arm(hir_vec![pinned_pat], loop_expr);
+
+        // match <expr> {
+        //     mut pinned => loop { .. }
+        // }
+        let expr = P(self.lower_expr(expr));
+        hir::ExprKind::Match(expr, hir_vec![pinned_arm], hir::MatchSource::AwaitDesugar)
     }
 
     fn lower_expr_closure(
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 17bcb1d..d1cc7a8 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -31,7 +31,7 @@
         self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
     }
 
-    pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
+    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
         let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def);
         f(self);
         self.parent_def = orig_parent_def;
@@ -74,6 +74,22 @@
         })
     }
 
+    fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
+        if field.is_placeholder {
+            self.visit_macro_invoc(field.id);
+        } else {
+            let name = field.ident.map(|ident| ident.name)
+                .or_else(|| index.map(sym::integer))
+                .unwrap_or_else(|| {
+                    let node_id = NodeId::placeholder_from_expn_id(self.expansion);
+                    sym::integer(self.definitions.placeholder_field_indices[&node_id])
+                })
+                .as_interned_str();
+            let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span);
+            self.with_parent(def, |this| visit::walk_struct_field(this, field));
+        }
+    }
+
     pub fn visit_macro_invoc(&mut self, id: NodeId) {
         self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
     }
@@ -155,6 +171,9 @@
     }
 
     fn visit_variant(&mut self, v: &'a Variant) {
+        if v.is_placeholder {
+            return self.visit_macro_invoc(v.id);
+        }
         let def = self.create_def(v.id,
                                   DefPathData::TypeNs(v.ident.as_interned_str()),
                                   v.span);
@@ -167,17 +186,22 @@
     }
 
     fn visit_variant_data(&mut self, data: &'a VariantData) {
+        // The assumption here is that non-`cfg` macro expansion cannot change field indices.
+        // It currently holds because only inert attributes are accepted on fields,
+        // and every such attribute expands into a single field after it's resolved.
         for (index, field) in data.fields().iter().enumerate() {
-            let name = field.ident.map(|ident| ident.name)
-                .unwrap_or_else(|| sym::integer(index));
-            let def = self.create_def(field.id,
-                                      DefPathData::ValueNs(name.as_interned_str()),
-                                      field.span);
-            self.with_parent(def, |this| this.visit_struct_field(field));
+            self.collect_field(field, Some(index));
+            if field.is_placeholder && field.ident.is_none() {
+                self.definitions.placeholder_field_indices.insert(field.id, index);
+            }
         }
     }
 
     fn visit_generic_param(&mut self, param: &'a GenericParam) {
+        if param.is_placeholder {
+            self.visit_macro_invoc(param.id);
+            return;
+        }
         let name = param.ident.as_interned_str();
         let def_path_data = match param.kind {
             GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name),
@@ -294,4 +318,42 @@
             }
         }
     }
+
+    fn visit_arm(&mut self, arm: &'a Arm) {
+        if arm.is_placeholder {
+            self.visit_macro_invoc(arm.id)
+        } else {
+            visit::walk_arm(self, arm)
+        }
+    }
+
+    fn visit_field(&mut self, f: &'a Field) {
+        if f.is_placeholder {
+            self.visit_macro_invoc(f.id)
+        } else {
+            visit::walk_field(self, f)
+        }
+    }
+
+    fn visit_field_pattern(&mut self, fp: &'a FieldPat) {
+        if fp.is_placeholder {
+            self.visit_macro_invoc(fp.id)
+        } else {
+            visit::walk_field_pattern(self, fp)
+        }
+    }
+
+    fn visit_param(&mut self, p: &'a Param) {
+        if p.is_placeholder {
+            self.visit_macro_invoc(p.id)
+        } else {
+            visit::walk_param(self, p)
+        }
+    }
+
+    // This method is called only when we are visiting an individual field
+    // after expanding an attribute on it.
+    fn visit_struct_field(&mut self, field: &'a StructField) {
+        self.collect_field(field, None);
+    }
 }
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 651fe84..187bc59 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -104,6 +104,8 @@
     /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
     /// we know what parent node that fragment should be attached to thanks to this table.
     invocation_parents: FxHashMap<ExpnId, DefIndex>,
+    /// Indices of unnamed struct or variant fields with unresolved attributes.
+    pub(super) placeholder_field_indices: NodeMap<usize>,
 }
 
 /// A unique identifier that we can use to lookup a definition
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index f5e6446..2c8590a 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -190,7 +190,7 @@
     Fresh(usize),
 
     /// Indicates an illegal name was given and an error has been
-    /// repored (so we should squelch other derived errors). Occurs
+    /// reported (so we should squelch other derived errors). Occurs
     /// when, e.g., `'_` is used in the wrong place.
     Error,
 }
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 5883be6..ab24b3f 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -55,7 +55,8 @@
 use crate::hir::Node;
 use crate::infer::opaque_types;
 use crate::middle::region;
-use crate::traits::{ObligationCause, ObligationCauseCode};
+use crate::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
+use crate::traits::{ObligationCauseCode};
 use crate::ty::error::TypeError;
 use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable};
 use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
@@ -624,13 +625,13 @@
                     }
                 }
             }
-            ObligationCauseCode::MatchExpressionArm {
+            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
                 source,
                 ref prior_arms,
                 last_ty,
                 discrim_hir_id,
                 ..
-            } => match source {
+            }) => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
                     let msg = "`if let` arms have incompatible types";
                     err.span_label(cause.span, msg);
@@ -681,7 +682,7 @@
                     }
                 }
             },
-            ObligationCauseCode::IfExpression { then, outer, semicolon } => {
+            ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => {
                 err.span_label(then, "expected because of this");
                 outer.map(|sp| err.span_label(sp, "if and else have incompatible types"));
                 if let Some(sp) = semicolon {
@@ -1622,13 +1623,15 @@
         use crate::traits::ObligationCauseCode::*;
         match self.code {
             CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
-            MatchExpressionArm { source, .. } => Error0308(match source {
-                hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types",
-                hir::MatchSource::TryDesugar => {
-                    "try expression alternatives have incompatible types"
-                }
-                _ => "match arms have incompatible types",
-            }),
+            MatchExpressionArm(box MatchExpressionArmCause { source, .. }) =>
+                Error0308(match source {
+                    hir::MatchSource::IfLetDesugar { .. } =>
+                        "`if let` arms have incompatible types",
+                    hir::MatchSource::TryDesugar => {
+                        "try expression alternatives have incompatible types"
+                    }
+                    _ => "match arms have incompatible types",
+                }),
             IfExpression { .. } => Error0308("if and else have incompatible types"),
             IfExpressionWithNoElse => Error0317("if may be missing an else clause"),
             MainFunctionType => Error0580("main function has wrong type"),
@@ -1656,7 +1659,7 @@
         match self.code {
             CompareImplMethodObligation { .. } => "method type is compatible with trait",
             ExprAssignable => "expression is assignable",
-            MatchExpressionArm { source, .. } => match source {
+            MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
                 hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",
                 _ => "match arms have compatible types",
             },
diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
index b4fb018..19bd38b 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -192,23 +192,28 @@
             vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
         );
 
-        let mut err = self.tcx().sess.struct_span_err(
-            cause.span(self.tcx()),
-            &format!(
-                "implementation of `{}` is not general enough",
-                self.tcx().def_path_str(trait_def_id),
-            ),
+        let span = cause.span(self.tcx());
+        let msg = format!(
+            "implementation of `{}` is not general enough",
+            self.tcx().def_path_str(trait_def_id),
+        );
+        let mut err = self.tcx().sess.struct_span_err(span, &msg);
+        err.span_label(
+            self.tcx().def_span(trait_def_id),
+            format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)),
         );
 
-        match cause.code {
-            ObligationCauseCode::ItemObligation(def_id) => {
-                err.note(&format!(
-                    "Due to a where-clause on `{}`,",
-                    self.tcx().def_path_str(def_id),
-                ));
-            }
-            _ => (),
-        }
+        let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code {
+            err.span_label(span, "doesn't satisfy where-clause");
+            err.span_label(
+                self.tcx().def_span(def_id),
+                &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
+            );
+            true
+        } else {
+            err.span_label(span, &msg);
+            false
+        };
 
         let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef {
             def_id: trait_def_id,
@@ -295,6 +300,7 @@
             expected_has_vid,
             actual_has_vid,
             any_self_ty_has_vid,
+            leading_ellipsis,
         );
 
         err
@@ -318,6 +324,7 @@
         expected_has_vid: Option<usize>,
         actual_has_vid: Option<usize>,
         any_self_ty_has_vid: bool,
+        leading_ellipsis: bool,
     ) {
         // HACK(eddyb) maybe move this in a more central location.
         #[derive(Copy, Clone)]
@@ -392,13 +399,15 @@
 
             let mut note = if passive_voice {
                 format!(
-                    "`{}` would have to be implemented for the type `{}`",
+                    "{}`{}` would have to be implemented for the type `{}`",
+                    if leading_ellipsis { "..." } else { "" },
                     expected_trait_ref,
                     expected_trait_ref.map(|tr| tr.self_ty()),
                 )
             } else {
                 format!(
-                    "`{}` must implement `{}`",
+                    "{}`{}` must implement `{}`",
+                    if leading_ellipsis { "..." } else { "" },
                     expected_trait_ref.map(|tr| tr.self_ty()),
                     expected_trait_ref,
                 )
@@ -407,20 +416,20 @@
             match (has_sub, has_sup) {
                 (Some(n1), Some(n2)) => {
                     let _ = write!(note,
-                        ", for any two lifetimes `'{}` and `'{}`",
+                        ", for any two lifetimes `'{}` and `'{}`...",
                         std::cmp::min(n1, n2),
                         std::cmp::max(n1, n2),
                     );
                 }
                 (Some(n), _) | (_, Some(n)) => {
                     let _ = write!(note,
-                        ", for any lifetime `'{}`",
+                        ", for any lifetime `'{}`...",
                         n,
                     );
                 }
                 (None, None) => if let Some(n) = expected_has_vid {
                     let _ = write!(note,
-                        ", for some specific lifetime `'{}`",
+                        ", for some specific lifetime `'{}`...",
                         n,
                     );
                 },
@@ -439,13 +448,13 @@
 
             let mut note = if passive_voice {
                 format!(
-                    "but `{}` is actually implemented for the type `{}`",
+                    "...but `{}` is actually implemented for the type `{}`",
                     actual_trait_ref,
                     actual_trait_ref.map(|tr| tr.self_ty()),
                 )
             } else {
                 format!(
-                    "but `{}` actually implements `{}`",
+                    "...but `{}` actually implements `{}`",
                     actual_trait_ref.map(|tr| tr.self_ty()),
                     actual_trait_ref,
                 )
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 63ef82a..7a01ae6 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -67,7 +67,6 @@
 
 #[macro_use] extern crate bitflags;
 extern crate getopts;
-#[macro_use] extern crate lazy_static;
 #[macro_use] extern crate scoped_tls;
 #[cfg(windows)]
 extern crate libc;
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 93bb301..ba27d33 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -16,16 +16,16 @@
 
     map: &'a hir_map::Map<'tcx>,
 
-    /// The top-level function called 'main'.
+    /// The top-level function called `main`.
     main_fn: Option<(HirId, Span)>,
 
-    /// The function that has attribute named 'main'.
+    /// The function that has attribute named `main`.
     attr_main_fn: Option<(HirId, Span)>,
 
     /// The function that has the attribute 'start' on it.
     start_fn: Option<(HirId, Span)>,
 
-    /// The functions that one might think are 'main' but aren't, e.g.
+    /// The functions that one might think are `main` but aren't, e.g.
     /// main functions not defined at the top level. For diagnostics.
     non_main_fns: Vec<(HirId, Span)> ,
 }
@@ -88,7 +88,7 @@
                 EntryPointType::MainAttr
             } else if item.ident.name == sym::main {
                 if at_root {
-                    // This is a top-level function so can be 'main'.
+                    // This is a top-level function so can be `main`.
                     EntryPointType::MainNamed
                 } else {
                     EntryPointType::OtherMain
@@ -109,7 +109,7 @@
                 ctxt.main_fn = Some((item.hir_id, item.span));
             } else {
                 span_err!(ctxt.session, item.span, E0136,
-                          "multiple 'main' functions");
+                          "multiple `main` functions");
             }
         },
         EntryPointType::OtherMain => {
@@ -130,7 +130,7 @@
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((item.hir_id, item.span));
             } else {
-                struct_span_err!(ctxt.session, item.span, E0138, "multiple 'start' functions")
+                struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
                     .span_label(ctxt.start_fn.unwrap().1, "previous `start` function here")
                     .span_label(item.span, "multiple `start` functions")
                     .emit();
@@ -148,34 +148,48 @@
     } else if let Some((hir_id, _)) = visitor.main_fn {
         Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
     } else {
-        // There is no main function.
-        let mut err = struct_err!(tcx.sess, E0601,
-            "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
-        if !visitor.non_main_fns.is_empty() {
-            // There were some functions named 'main' though. Try to give the user a hint.
-            err.note("the main function must be defined at the crate level \
-                      but you have one or more functions named 'main' that are not \
-                      defined at the crate level. Either move the definition or \
-                      attach the `#[main]` attribute to override this behavior.");
-            for &(_, span) in &visitor.non_main_fns {
-                err.span_note(span, "here is a function named 'main'");
-            }
-            err.emit();
-        } else {
-            if let Some(ref filename) = tcx.sess.local_crate_source_file {
-                err.note(&format!("consider adding a `main` function to `{}`", filename.display()));
-            }
-            if tcx.sess.teach(&err.get_code().unwrap()) {
-                err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
-                          to get started: https://doc.rust-lang.org/book/");
-            }
-            err.emit();
-        }
-
+        no_main_err(tcx, visitor);
         None
     }
 }
 
+fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+    // There is no main function.
+    let mut err = struct_err!(tcx.sess, E0601,
+        "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
+    let filename = &tcx.sess.local_crate_source_file;
+    let note = if !visitor.non_main_fns.is_empty() {
+        for &(_, span) in &visitor.non_main_fns {
+            err.span_note(span, "here is a function named `main`");
+        }
+        err.note("you have one or more functions named `main` not defined at the crate level");
+        err.help("either move the `main` function definitions or attach the `#[main]` attribute \
+                  to one of them");
+        // There were some functions named `main` though. Try to give the user a hint.
+        format!("the main function must be defined at the crate level{}",
+                 filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default())
+    } else if let Some(filename) = filename {
+        format!("consider adding a `main` function to `{}`", filename.display())
+    } else {
+        String::from("consider adding a `main` function at the crate level")
+    };
+    let sp = tcx.hir().krate().span;
+    // The file may be empty, which leads to the diagnostic machinery not emitting this
+    // note. This is a relatively simple way to detect that case and emit a span-less
+    // note instead.
+    if let Ok(_) = tcx.sess.source_map().lookup_line(sp.lo()) {
+        err.set_span(sp);
+        err.span_label(sp, &note);
+    } else {
+        err.note(&note);
+    }
+    if tcx.sess.teach(&err.get_code().unwrap()) {
+        err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
+                  to get started: https://doc.rust-lang.org/book/");
+    }
+    err.emit();
+}
+
 pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
     tcx.entry_fn(LOCAL_CRATE)
 }
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 4fb88da..fa5fa22 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -116,8 +116,8 @@
 }
 
 impl<'a, 'tcx> Context<'a, 'tcx> {
-    fn register(&mut self, name: &str, span: Span) {
-        $(if name == stringify!($name) {
+    fn register(&mut self, name: Symbol, span: Span) {
+        $(if name == sym::$name {
             if self.items.$name().is_none() {
                 self.items.missing.push(lang_items::$item);
             }
@@ -136,7 +136,7 @@
 
     fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
         if let Some((lang_item, _)) = lang_items::extract(&i.attrs) {
-            self.register(&lang_item.as_str(), i.span);
+            self.register(lang_item, i.span);
         }
         intravisit::walk_foreign_item(self, i)
     }
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 09c822f..67b3ce0 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -213,6 +213,15 @@
     eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
 }
 
+impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
+    fn from(err: ErrorHandled) -> Self {
+        match err {
+            ErrorHandled::Reported => err_inval!(ReferencedConstant),
+            ErrorHandled::TooGeneric => err_inval!(TooGeneric),
+        }.into()
+    }
+}
+
 impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
     fn from(kind: InterpError<'tcx>) -> Self {
         let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index d72d879..b8bc741 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -17,8 +17,8 @@
     pub ty: Ty<'tcx>,
 }
 
-/// Represents a constant value in Rust. `Scalar` and `ScalarPair` are optimizations that
-/// match the `LocalState` optimizations for easy conversions between `Value` and `ConstValue`.
+/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
+/// array length computations, enum discriminants and the pattern matching logic.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord,
          RustcEncodable, RustcDecodable, Hash, HashStable)]
 pub enum ConstValue<'tcx> {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 18a5142..0ebc707 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -32,7 +32,6 @@
 use smallvec::SmallVec;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Display, Formatter, Write};
-use std::iter::FusedIterator;
 use std::ops::{Index, IndexMut};
 use std::slice;
 use std::vec::IntoIter;
@@ -1548,7 +1547,7 @@
 
 // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(Statement<'_>, 56);
+static_assert_size!(Statement<'_>, 32);
 
 impl Statement<'_> {
     /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -1569,7 +1568,7 @@
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub enum StatementKind<'tcx> {
     /// Write the RHS Rvalue to the LHS Place.
-    Assign(Place<'tcx>, Box<Rvalue<'tcx>>),
+    Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
 
     /// This represents all the reading that a pattern match may do
     /// (e.g., inspecting constants and discriminant values), and the
@@ -1578,10 +1577,10 @@
     ///
     /// Note that this also is emitted for regular `let` bindings to ensure that locals that are
     /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
-    FakeRead(FakeReadCause, Place<'tcx>),
+    FakeRead(FakeReadCause, Box<Place<'tcx>>),
 
     /// Write the discriminant for a variant to the enum Place.
-    SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx },
+    SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
 
     /// Start a live range for the storage of the local.
     StorageLive(Local),
@@ -1598,7 +1597,7 @@
     /// by miri and only generated when "-Z mir-emit-retag" is passed.
     /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
     /// for more details.
-    Retag(RetagKind, Place<'tcx>),
+    Retag(RetagKind, Box<Place<'tcx>>),
 
     /// Encodes a user's type ascription. These need to be preserved
     /// intact so that NLL can respect them. For example:
@@ -1612,7 +1611,7 @@
     /// - `Contravariant` -- requires that `T_y :> T`
     /// - `Invariant` -- requires that `T_y == T`
     /// - `Bivariant` -- no effect
-    AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>),
+    AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
@@ -1676,7 +1675,7 @@
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         use self::StatementKind::*;
         match self.kind {
-            Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
+            Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
             FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
             Retag(ref kind, ref place) => write!(
                 fmt,
@@ -1697,7 +1696,7 @@
             InlineAsm(ref asm) => {
                 write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
             }
-            AscribeUserType(ref place, ref variance, ref c_ty) => {
+            AscribeUserType(box(ref place, ref c_ty), ref variance) => {
                 write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
             }
             Nop => write!(fmt, "nop"),
@@ -1717,7 +1716,7 @@
     pub base: PlaceBase<'tcx>,
 
     /// projection out of a place (access a field, deref a pointer, etc)
-    pub projection: Option<Box<Projection<'tcx>>>,
+    pub projection: Box<[PlaceElem<'tcx>]>,
 }
 
 #[derive(
@@ -1760,15 +1759,6 @@
     def_id
 });
 
-/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`.
-#[derive(
-    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
-)]
-pub struct Projection<'tcx> {
-    pub base: Option<Box<Projection<'tcx>>>,
-    pub elem: PlaceElem<'tcx>,
-}
-
 #[derive(
     Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
 )]
@@ -1850,14 +1840,22 @@
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct PlaceRef<'a, 'tcx> {
     pub base: &'a PlaceBase<'tcx>,
-    pub projection: &'a Option<Box<Projection<'tcx>>>,
+    pub projection: &'a [PlaceElem<'tcx>],
 }
 
 impl<'tcx> Place<'tcx> {
-    pub const RETURN_PLACE: Place<'tcx> = Place {
-        base: PlaceBase::Local(RETURN_PLACE),
-        projection: None,
-    };
+    // FIXME change this back to a const when projection is a shared slice.
+    //
+    // pub const RETURN_PLACE: Place<'tcx> = Place {
+    //     base: PlaceBase::Local(RETURN_PLACE),
+    //     projection: &[],
+    // };
+    pub fn return_place() -> Place<'tcx> {
+        Place {
+            base: PlaceBase::Local(RETURN_PLACE),
+            projection: Box::new([]),
+        }
+    }
 
     pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
         self.elem(ProjectionElem::Field(f, ty))
@@ -1883,9 +1881,13 @@
     }
 
     pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
+        // FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
+        let mut projection = self.projection.into_vec();
+        projection.push(elem);
+
         Place {
             base: self.base,
-            projection: Some(Box::new(Projection { base: self.projection, elem })),
+            projection: projection.into_boxed_slice(),
         }
     }
 
@@ -1894,7 +1896,7 @@
     /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
     /// same region of memory as its base.
     pub fn is_indirect(&self) -> bool {
-        self.iterate(|_, mut projections| projections.any(|proj| proj.elem.is_indirect()))
+        self.projection.iter().any(|elem| elem.is_indirect())
     }
 
     /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
@@ -1905,61 +1907,16 @@
         match self {
             Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             } |
             Place {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: box [ProjectionElem::Deref],
             } => Some(*local),
             _ => None,
         }
     }
 
-    /// Recursively "iterates" over place components, generating a `PlaceBase` and
-    /// `Projections` list and invoking `op` with a `ProjectionsIter`.
-    pub fn iterate<R>(
-        &self,
-        op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-    ) -> R {
-        Place::iterate_over(&self.base, &self.projection, op)
-    }
-
-    pub fn iterate_over<R>(
-        place_base: &PlaceBase<'tcx>,
-        place_projection: &Option<Box<Projection<'tcx>>>,
-        op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-    ) -> R {
-        fn iterate_over2<'tcx, R>(
-            place_base: &PlaceBase<'tcx>,
-            place_projection: &Option<Box<Projection<'tcx>>>,
-            next: &Projections<'_, 'tcx>,
-            op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-        ) -> R {
-            match place_projection {
-                None => {
-                    op(place_base, next.iter())
-                }
-
-                Some(interior) => {
-                    iterate_over2(
-                        place_base,
-                        &interior.base,
-                        &Projections::List {
-                            projection: interior,
-                            next,
-                        },
-                        op,
-                    )
-                }
-            }
-        }
-
-        iterate_over2(place_base, place_projection, &Projections::Empty, op)
-    }
-
     pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
         PlaceRef {
             base: &self.base,
@@ -1972,7 +1929,7 @@
     fn from(local: Local) -> Self {
         Place {
             base: local.into(),
-            projection: None,
+            projection: Box::new([]),
         }
     }
 }
@@ -1984,13 +1941,6 @@
 }
 
 impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
-    pub fn iterate<R>(
-        &self,
-        op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
-    ) -> R {
-        Place::iterate_over(self.base, self.projection, op)
-    }
-
     /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
     /// a single deref of a local.
     //
@@ -1999,143 +1949,71 @@
         match self {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } |
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             } => Some(*local),
             _ => None,
         }
     }
 }
 
-/// A linked list of projections running up the stack; begins with the
-/// innermost projection and extends to the outermost (e.g., `a.b.c`
-/// would have the place `b` with a "next" pointer to `b.c`).
-/// Created by `Place::iterate`.
-///
-/// N.B., this particular impl strategy is not the most obvious. It was
-/// chosen because it makes a measurable difference to NLL
-/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
-pub enum Projections<'p, 'tcx> {
-    Empty,
-
-    List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> },
-}
-
-impl<'p, 'tcx> Projections<'p, 'tcx> {
-    fn iter(&self) -> ProjectionsIter<'_, 'tcx> {
-        ProjectionsIter { value: self }
-    }
-}
-
-impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> {
-    type Item = &'p Projection<'tcx>;
-    type IntoIter = ProjectionsIter<'p, 'tcx>;
-
-    /// Converts a list of `Projection` components into an iterator;
-    /// this iterator yields up a never-ending stream of `Option<&Place>`.
-    /// These begin with the "innermost" projection and then with each
-    /// projection therefrom. So given a place like `a.b.c` it would
-    /// yield up:
-    ///
-    /// ```notrust
-    /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
-    /// ```
-    fn into_iter(self) -> Self::IntoIter {
-        self.iter()
-    }
-}
-
-/// Iterator over components; see `Projections::iter` for more
-/// information.
-///
-/// N.B., this is not a *true* Rust iterator -- the code above just
-/// manually invokes `next`. This is because we (sometimes) want to
-/// keep executing even after `None` has been returned.
-pub struct ProjectionsIter<'p, 'tcx> {
-    pub value: &'p Projections<'p, 'tcx>,
-}
-
-impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> {
-    type Item = &'p Projection<'tcx>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let &Projections::List { projection, next } = self.value {
-            self.value = next;
-            Some(projection)
-        } else {
-            None
-        }
-    }
-}
-
-impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {}
-
 impl Debug for Place<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        self.iterate(|_place_base, place_projections| {
-            // FIXME: remove this collect once we have migrated to slices
-            let projs_vec: Vec<_> = place_projections.collect();
-            for projection in projs_vec.iter().rev() {
-                match projection.elem {
-                    ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
-                        write!(fmt, "(").unwrap();
-                    }
-                    ProjectionElem::Deref => {
-                        write!(fmt, "(*").unwrap();
-                    }
-                    ProjectionElem::Index(_)
-                    | ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. } => {}
+        for elem in self.projection.iter().rev() {
+            match elem {
+                ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
+                    write!(fmt, "(").unwrap();
+                }
+                ProjectionElem::Deref => {
+                    write!(fmt, "(*").unwrap();
+                }
+                ProjectionElem::Index(_)
+                | ProjectionElem::ConstantIndex { .. }
+                | ProjectionElem::Subslice { .. } => {}
+            }
+        }
+
+        write!(fmt, "{:?}", self.base)?;
+
+        for elem in self.projection.iter() {
+            match elem {
+                ProjectionElem::Downcast(Some(name), _index) => {
+                    write!(fmt, " as {})", name)?;
+                }
+                ProjectionElem::Downcast(None, index) => {
+                    write!(fmt, " as variant#{:?})", index)?;
+                }
+                ProjectionElem::Deref => {
+                    write!(fmt, ")")?;
+                }
+                ProjectionElem::Field(field, ty) => {
+                    write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
+                }
+                ProjectionElem::Index(ref index) => {
+                    write!(fmt, "[{:?}]", index)?;
+                }
+                ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
+                    write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
+                }
+                ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
+                    write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
+                }
+                ProjectionElem::Subslice { from, to } if *to == 0 => {
+                    write!(fmt, "[{:?}:]", from)?;
+                }
+                ProjectionElem::Subslice { from, to } if *from == 0 => {
+                    write!(fmt, "[:-{:?}]", to)?;
+                }
+                ProjectionElem::Subslice { from, to } => {
+                    write!(fmt, "[{:?}:-{:?}]", from, to)?;
                 }
             }
-        });
+        }
 
-        self.iterate(|place_base, place_projections| {
-            write!(fmt, "{:?}", place_base)?;
-
-            for projection in place_projections {
-                match projection.elem {
-                    ProjectionElem::Downcast(Some(name), _index) => {
-                        write!(fmt, " as {})", name)?;
-                    }
-                    ProjectionElem::Downcast(None, index) => {
-                        write!(fmt, " as variant#{:?})", index)?;
-                    }
-                    ProjectionElem::Deref => {
-                        write!(fmt, ")")?;
-                    }
-                    ProjectionElem::Field(field, ty) => {
-                        write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
-                    }
-                    ProjectionElem::Index(ref index) => {
-                        write!(fmt, "[{:?}]", index)?;
-                    }
-                    ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
-                        write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
-                    }
-                    ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
-                        write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
-                    }
-                    ProjectionElem::Subslice { from, to } if to == 0 => {
-                        write!(fmt, "[{:?}:]", from)?;
-                    }
-                    ProjectionElem::Subslice { from, to } if from == 0 => {
-                        write!(fmt, "[:-{:?}]", to)?;
-                    }
-                    ProjectionElem::Subslice { from, to } => {
-                        write!(fmt, "[{:?}:-{:?}]", from, to)?;
-                    }
-                }
-            }
-
-            Ok(())
-        })
+        Ok(())
     }
 }
 
@@ -3120,14 +2998,14 @@
 
 EnumTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
-        (StatementKind::Assign)(a, b),
+        (StatementKind::Assign)(a),
         (StatementKind::FakeRead)(cause, place),
         (StatementKind::SetDiscriminant) { place, variant_index },
         (StatementKind::StorageLive)(a),
         (StatementKind::StorageDead)(a),
         (StatementKind::InlineAsm)(a),
         (StatementKind::Retag)(kind, place),
-        (StatementKind::AscribeUserType)(a, v, b),
+        (StatementKind::AscribeUserType)(a, v),
         (StatementKind::Nop),
     }
 }
@@ -3409,30 +3287,26 @@
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         use crate::mir::ProjectionElem::*;
 
-        let base = self.base.fold_with(folder);
-        let elem = match self.elem {
+        match self {
             Deref => Deref,
-            Field(f, ref ty) => Field(f, ty.fold_with(folder)),
-            Index(ref v) => Index(v.fold_with(folder)),
-            ref elem => elem.clone(),
-        };
-
-        Projection { base, elem }
+            Field(f, ty) => Field(*f, ty.fold_with(folder)),
+            Index(v) => Index(v.fold_with(folder)),
+            elem => elem.clone(),
+        }
     }
 
     fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
         use crate::mir::ProjectionElem::*;
 
-        self.base.visit_with(visitor)
-            || match self.elem {
-                Field(_, ref ty) => ty.visit_with(visitor),
-                Index(ref v) => v.visit_with(visitor),
-                _ => false,
-            }
+        match self {
+            Field(_, ty) => ty.visit_with(visitor),
+            Index(v) => v.visit_with(visitor),
+            _ => false,
+        }
     }
 }
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index e9f7636..d776809 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -121,21 +121,16 @@
 impl<'tcx> Place<'tcx> {
     pub fn ty_from<D>(
         base: &PlaceBase<'tcx>,
-        projection: &Option<Box<Projection<'tcx>>>,
+        projection: &[PlaceElem<'tcx>],
         local_decls: &D,
         tcx: TyCtxt<'tcx>
     ) -> PlaceTy<'tcx>
         where D: HasLocalDecls<'tcx>
     {
-        Place::iterate_over(base, projection, |place_base, place_projections| {
-            let mut place_ty = place_base.ty(local_decls);
-
-            for proj in place_projections {
-                place_ty = place_ty.projection_ty(tcx, &proj.elem);
-            }
-
-            place_ty
-        })
+        projection.iter().fold(
+            base.ty(local_decls),
+            |place_ty, elem| place_ty.projection_ty(tcx, elem)
+        )
     }
 
     pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 821367e..1e3b9eb 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -152,18 +152,18 @@
             }
 
             fn visit_place_base(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
+                                base: & $($mutability)? PlaceBase<'tcx>,
                                 context: PlaceContext,
                                 location: Location) {
-                self.super_place_base(place_base, context, location);
+                self.super_place_base(base, context, location);
             }
 
             fn visit_projection(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
-                                place: & $($mutability)? Projection<'tcx>,
+                                base: & $($mutability)? PlaceBase<'tcx>,
+                                projection: & $($mutability)? [PlaceElem<'tcx>],
                                 context: PlaceContext,
                                 location: Location) {
-                self.super_projection(place_base, place, context, location);
+                self.super_projection(base, projection, context, location);
             }
 
             fn visit_constant(&mut self,
@@ -344,7 +344,9 @@
 
                 self.visit_source_info(source_info);
                 match kind {
-                    StatementKind::Assign(place, rvalue) => {
+                    StatementKind::Assign(
+                        box(ref $($mutability)? place, ref $($mutability)? rvalue)
+                    ) => {
                         self.visit_assign(place, rvalue, location);
                     }
                     StatementKind::FakeRead(_, place) => {
@@ -391,7 +393,10 @@
                     StatementKind::Retag(kind, place) => {
                         self.visit_retag(kind, place, location);
                     }
-                    StatementKind::AscribeUserType(place, variance, user_ty) => {
+                    StatementKind::AscribeUserType(
+                        box(ref $($mutability)? place, ref $($mutability)? user_ty),
+                        variance
+                    ) => {
                         self.visit_ascribe_user_ty(place, variance, user_ty, location);
                     }
                     StatementKind::Nop => {}
@@ -685,7 +690,7 @@
                             location: Location) {
                 let mut context = context;
 
-                if place.projection.is_some() {
+                if !place.projection.is_empty() {
                     context = if context.is_mutating_use() {
                         PlaceContext::MutatingUse(MutatingUseContext::Projection)
                     } else {
@@ -695,9 +700,10 @@
 
                 self.visit_place_base(& $($mutability)? place.base, context, location);
 
-                if let Some(box proj) = & $($mutability)? place.projection {
-                    self.visit_projection(& $($mutability)? place.base, proj, context, location);
-                }
+                self.visit_projection(& $($mutability)? place.base,
+                                      & $($mutability)? place.projection,
+                                      context,
+                                      location);
             }
 
             fn super_place_base(&mut self,
@@ -715,31 +721,31 @@
             }
 
             fn super_projection(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
-                                proj: & $($mutability)? Projection<'tcx>,
+                                base: & $($mutability)? PlaceBase<'tcx>,
+                                projection: & $($mutability)? [PlaceElem<'tcx>],
                                 context: PlaceContext,
                                 location: Location) {
-                if let Some(box proj_base) = & $($mutability)? proj.base {
-                    self.visit_projection(place_base, proj_base, context, location);
-                }
+                if let [proj_base @ .., elem] = projection {
+                    self.visit_projection(base, proj_base, context, location);
 
-                match & $($mutability)? proj.elem {
-                    ProjectionElem::Field(_field, ty) => {
-                        self.visit_ty(ty, TyContext::Location(location));
-                    }
-                    ProjectionElem::Index(local) => {
-                        self.visit_local(
-                            local,
-                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
-                            location
-                        );
-                    }
-                    ProjectionElem::Deref |
-                    ProjectionElem::Subslice { from: _, to: _ } |
-                    ProjectionElem::ConstantIndex { offset: _,
-                                                    min_length: _,
-                                                    from_end: _ } |
-                    ProjectionElem::Downcast(_, _) => {
+                    match elem {
+                        ProjectionElem::Field(_field, ty) => {
+                            self.visit_ty(ty, TyContext::Location(location));
+                        }
+                        ProjectionElem::Index(local) => {
+                            self.visit_local(
+                                local,
+                                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+                                location
+                            );
+                        }
+                        ProjectionElem::Deref |
+                        ProjectionElem::Subslice { from: _, to: _ } |
+                        ProjectionElem::ConstantIndex { offset: _,
+                                                        min_length: _,
+                                                        from_end: _ } |
+                        ProjectionElem::Downcast(_, _) => {
+                        }
                     }
                 }
             }
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 4ebc2e7..c726094 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -462,15 +462,6 @@
             no_force
             desc { "extract field of const" }
         }
-
-        /// Produces an absolute path representation of the given type. See also the documentation
-        /// on `std::any::type_name`.
-        query type_name(key: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
-            eval_always
-            no_force
-            desc { "get absolute path of type" }
-        }
-
     }
 
     TypeChecking {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index c74b2fe..723855c 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -7,6 +7,7 @@
 use crate::session::search_paths::SearchPath;
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
 
 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
 use rustc_target::spec::{Target, TargetTriple};
@@ -19,6 +20,7 @@
 use syntax::parse::token;
 use syntax::symbol::{sym, Symbol};
 use syntax::feature_gate::UnstableFeatures;
+use syntax::source_map::SourceMap;
 
 use errors::emitter::HumanReadableErrorType;
 use errors::{ColorConfig, FatalError, Handler};
@@ -1850,11 +1852,20 @@
     opts
 }
 
+struct NullEmitter;
+
+impl errors::emitter::Emitter for NullEmitter {
+    fn emit_diagnostic(&mut self, _: &errors::DiagnosticBuilder<'_>) {}
+}
+
 // Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
 pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
     syntax::with_default_globals(move || {
         let cfg = cfgspecs.into_iter().map(|s| {
-            let sess = ParseSess::new(FilePathMapping::empty());
+
+            let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+            let handler = Handler::with_emitter(false, None, Box::new(NullEmitter));
+            let sess = ParseSess::with_span_handler(handler, cm);
             let filename = FileName::cfg_spec_source_code(&s);
             let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
 
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index c1de493..4494c03 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -68,6 +68,10 @@
     pub stalled_on: Vec<Ty<'tcx>>,
 }
 
+// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PendingPredicateObligation<'_>, 136);
+
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
     pub fn new() -> FulfillmentContext<'tcx> {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 1ca92d7..d268309 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -123,6 +123,10 @@
 pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
 pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 
+// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PredicateObligation<'_>, 112);
+
 /// The reason why we incurred this obligation; used for error reporting.
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct ObligationCause<'tcx> {
@@ -147,7 +151,8 @@
             ObligationCauseCode::StartFunctionType => {
                 tcx.sess.source_map().def_span(self.span)
             }
-            ObligationCauseCode::MatchExpressionArm { arm_span, .. } => arm_span,
+            ObligationCauseCode::MatchExpressionArm(
+                box MatchExpressionArmCause { arm_span, .. }) => arm_span,
             _ => self.span,
         }
     }
@@ -223,23 +228,13 @@
     ExprAssignable,
 
     /// Computing common supertype in the arms of a match expression
-    MatchExpressionArm {
-        arm_span: Span,
-        source: hir::MatchSource,
-        prior_arms: Vec<Span>,
-        last_ty: Ty<'tcx>,
-        discrim_hir_id: hir::HirId,
-    },
+    MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
 
     /// Computing common supertype in the pattern guard for the arms of a match expression
     MatchExpressionArmPattern { span: Span, ty: Ty<'tcx> },
 
     /// Computing common supertype in an if expression
-    IfExpression {
-        then: Span,
-        outer: Option<Span>,
-        semicolon: Option<Span>,
-    },
+    IfExpression(Box<IfExpressionCause>),
 
     /// Computing common supertype of an if expression with no else counter-part
     IfExpressionWithNoElse,
@@ -269,6 +264,26 @@
     TrivialBound,
 }
 
+// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(ObligationCauseCode<'_>, 32);
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct MatchExpressionArmCause<'tcx> {
+    pub arm_span: Span,
+    pub source: hir::MatchSource,
+    pub prior_arms: Vec<Span>,
+    pub last_ty: Ty<'tcx>,
+    pub discrim_hir_id: hir::HirId,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct IfExpressionCause {
+    pub then: Span,
+    pub outer: Option<Span>,
+    pub semicolon: Option<Span>,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct DerivedObligationCause<'tcx> {
     /// The trait reference of the parent obligation that led to the
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 05b698e..6930c93 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -508,31 +508,33 @@
                 trait_item_def_id,
             }),
             super::ExprAssignable => Some(super::ExprAssignable),
-            super::MatchExpressionArm {
+            super::MatchExpressionArm(box super::MatchExpressionArmCause {
                 arm_span,
                 source,
                 ref prior_arms,
                 last_ty,
                 discrim_hir_id,
-            } => {
+            }) => {
                 tcx.lift(&last_ty).map(|last_ty| {
-                    super::MatchExpressionArm {
+                    super::MatchExpressionArm(box super::MatchExpressionArmCause {
                         arm_span,
                         source,
                         prior_arms: prior_arms.clone(),
                         last_ty,
                         discrim_hir_id,
-                    }
+                    })
                 })
             }
             super::MatchExpressionArmPattern { span, ty } => {
                 tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty })
             }
-            super::IfExpression { then, outer, semicolon } => Some(super::IfExpression {
-                then,
-                outer,
-                semicolon,
-            }),
+            super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => {
+                Some(super::IfExpression(box super::IfExpressionCause {
+                    then,
+                    outer,
+                    semicolon,
+                }))
+            }
             super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
             super::MainFunctionType => Some(super::MainFunctionType),
             super::StartFunctionType => Some(super::StartFunctionType),
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 8e8472a..0155803 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -205,26 +205,24 @@
 fn validate_hir_id_for_typeck_tables(local_id_root: Option<DefId>,
                                      hir_id: hir::HirId,
                                      mut_access: bool) {
-    if cfg!(debug_assertions) {
-        if let Some(local_id_root) = local_id_root {
-            if hir_id.owner != local_id_root.index {
-                ty::tls::with(|tcx| {
-                    bug!("node {} with HirId::owner {:?} cannot be placed in \
-                          TypeckTables with local_id_root {:?}",
-                         tcx.hir().node_to_string(hir_id),
-                         DefId::local(hir_id.owner),
-                         local_id_root)
-                });
-            }
-        } else {
-            // We use "Null Object" TypeckTables in some of the analysis passes.
-            // These are just expected to be empty and their `local_id_root` is
-            // `None`. Therefore we cannot verify whether a given `HirId` would
-            // be a valid key for the given table. Instead we make sure that
-            // nobody tries to write to such a Null Object table.
-            if mut_access {
-                bug!("access to invalid TypeckTables")
-            }
+    if let Some(local_id_root) = local_id_root {
+        if hir_id.owner != local_id_root.index {
+            ty::tls::with(|tcx| {
+                bug!("node {} with HirId::owner {:?} cannot be placed in \
+                        TypeckTables with local_id_root {:?}",
+                        tcx.hir().node_to_string(hir_id),
+                        DefId::local(hir_id.owner),
+                        local_id_root)
+            });
+        }
+    } else {
+        // We use "Null Object" TypeckTables in some of the analysis passes.
+        // These are just expected to be empty and their `local_id_root` is
+        // `None`. Therefore we cannot verify whether a given `HirId` would
+        // be a valid key for the given table. Instead we make sure that
+        // nobody tries to write to such a Null Object table.
+        if mut_access {
+            bug!("access to invalid TypeckTables")
         }
     }
 }
@@ -2396,9 +2394,9 @@
     }
 
     #[inline]
-    pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem)  -> Ty<'tcx> {
-        let def_id = self.require_lang_item(item, None);
-        self.mk_generic_adt(def_id, ty)
+    pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem)  -> Option<Ty<'tcx>> {
+        let def_id = self.lang_items().require(item).ok()?;
+        Some(self.mk_generic_adt(def_id, ty))
     }
 
     #[inline]
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index f67526e..62910ec 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -4,6 +4,7 @@
 use std::fmt;
 use rustc_target::spec::abi;
 use syntax::ast;
+use syntax::errors::pluralise;
 use errors::{Applicability, DiagnosticBuilder};
 use syntax_pos::Span;
 
@@ -82,12 +83,6 @@
             }
         };
 
-        macro_rules! pluralise {
-            ($x:expr) => {
-                if $x != 1 { "s" } else { "" }
-            };
-        }
-
         match *self {
             CyclicTy(_) => write!(f, "cyclic type of infinite size"),
             Mismatch => write!(f, "types differ"),
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 41e4295..5ca819e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1938,9 +1938,15 @@
     pub vis: Visibility,
 }
 
-/// The definition of an abstract data type -- a struct or enum.
+/// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`.
 ///
 /// These are all interned (by `intern_adt_def`) into the `adt_defs` table.
+///
+/// The initialism *"Adt"* stands for an [*algebraic data type (ADT)*][adt].
+/// This is slightly wrong because `union`s are not ADTs.
+/// Moreover, Rust only allows recursive data types through indirection.
+///
+/// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type
 pub struct AdtDef {
     /// `DefId` of the struct, enum or union item.
     pub did: DefId,
@@ -2894,6 +2900,13 @@
     pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId)
                                         -> Option<ImplOverlapKind>
     {
+        // If either trait impl references an error, they're allowed to overlap,
+        // as one of them essentially doesn't exist.
+        if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error()) ||
+            self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error()) {
+            return Some(ImplOverlapKind::Permitted);
+        }
+
         let is_legit = if self.features().overlapping_marker_traits {
             let trait1_is_empty = self.impl_trait_ref(def_id1)
                 .map_or(false, |trait_ref| {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index a08c82a..78d94df 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -996,6 +996,24 @@
         debug!("is_type_representable: {:?} is {:?}", self, r);
         r
     }
+
+    /// Peel off all reference types in this type until there are none left.
+    ///
+    /// This method is idempotent, i.e. `ty.peel_refs().peel_refs() == ty.peel_refs()`.
+    ///
+    /// # Examples
+    ///
+    /// - `u8` -> `u8`
+    /// - `&'a mut u8` -> `u8`
+    /// - `&'a &'b u8` -> `u8`
+    /// - `&'a *const &'b u8 -> *const &'b u8`
+    pub fn peel_refs(&'tcx self) -> Ty<'tcx> {
+        let mut ty = self;
+        while let Ref(_, inner_ty, _) = ty.sty {
+            ty = inner_ty;
+        }
+        ty
+    }
 }
 
 fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 7118d05..2475b93 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -5,17 +5,13 @@
 use std::cell::{RefCell, Cell};
 use std::fmt::Debug;
 use std::hash::Hash;
-use std::panic;
-use std::env;
 use std::time::{Duration, Instant};
 
 use std::sync::mpsc::{Sender};
 use syntax_pos::{SpanData};
 use syntax::symbol::{Symbol, sym};
 use rustc_macros::HashStable;
-use crate::ty::TyCtxt;
 use crate::dep_graph::{DepNode};
-use lazy_static;
 use crate::session::Session;
 
 #[cfg(test)]
@@ -31,39 +27,6 @@
 
 thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
 
-lazy_static! {
-    static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
-        let hook = panic::take_hook();
-        panic::set_hook(Box::new(panic_hook));
-        hook
-    };
-}
-
-fn panic_hook(info: &panic::PanicInfo<'_>) {
-    (*DEFAULT_HOOK)(info);
-
-    let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
-
-    if backtrace {
-        TyCtxt::try_print_query_stack();
-    }
-
-    #[cfg(windows)]
-    unsafe {
-        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
-            extern "system" {
-                fn DebugBreak();
-            }
-            // Trigger a debugger if we crashed during bootstrap.
-            DebugBreak();
-        }
-    }
-}
-
-pub fn install_panic_hook() {
-    lazy_static::initialize(&DEFAULT_HOOK);
-}
-
 /// Parameters to the `Dump` variant of type `ProfileQueriesMsg`.
 #[derive(Clone,Debug)]
 pub struct ProfQDumpParams {
diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs
index cc856ba..645707c 100644
--- a/src/librustc_asan/build.rs
+++ b/src/librustc_asan/build.rs
@@ -4,6 +4,7 @@
 use cmake::Config;
 
 fn main() {
+    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
     if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
         return;
     }
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index ff87afe..2ca517d 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -229,7 +229,7 @@
                 // We instead thus allocate some scratch space...
                 let scratch_size = cast.size(bx);
                 let scratch_align = cast.align(bx);
-                let llscratch = bx.alloca(cast.llvm_type(bx), "abi_cast", scratch_align);
+                let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
                 bx.lifetime_start(llscratch, scratch_size);
 
                 // ...where we first store the value...
diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs
index e3b7cb2..68d3f90 100644
--- a/src/librustc_codegen_llvm/back/archive.rs
+++ b/src/librustc_codegen_llvm/back/archive.rs
@@ -12,6 +12,7 @@
 use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
 use rustc_codegen_ssa::back::archive::{ArchiveBuilder, find_library};
 use rustc::session::Session;
+use syntax::symbol::Symbol;
 
 struct ArchiveConfig<'a> {
     pub sess: &'a Session,
@@ -109,7 +110,7 @@
 
     /// Adds all of the contents of a native library to this archive. This will
     /// search in the relevant locations for a library named `name`.
-    fn add_native_library(&mut self, name: &str) {
+    fn add_native_library(&mut self, name: Symbol) {
         let location = find_library(name, &self.config.lib_search_paths,
                                     self.config.sess);
         self.add_archive(&location, |_| false).unwrap_or_else(|e| {
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index e13a5ec..423a01a 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -387,23 +387,17 @@
         )
     }
 
-    fn alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
+    fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
         let mut bx = Builder::with_cx(self.cx);
         bx.position_at_start(unsafe {
             llvm::LLVMGetFirstBasicBlock(self.llfn())
         });
-        bx.dynamic_alloca(ty, name, align)
+        bx.dynamic_alloca(ty, align)
     }
 
-    fn dynamic_alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
+    fn dynamic_alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
         unsafe {
-            let alloca = if name.is_empty() {
-                llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED)
-            } else {
-                let name = SmallCStr::new(name);
-                llvm::LLVMBuildAlloca(self.llbuilder, ty,
-                                      name.as_ptr())
-            };
+            let alloca = llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED);
             llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
             alloca
         }
@@ -412,16 +406,9 @@
     fn array_alloca(&mut self,
                         ty: &'ll Type,
                         len: &'ll Value,
-                        name: &str,
                         align: Align) -> &'ll Value {
         unsafe {
-            let alloca = if name.is_empty() {
-                llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED)
-            } else {
-                let name = SmallCStr::new(name);
-                llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len,
-                                           name.as_ptr())
-            };
+            let alloca = llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED);
             llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
             alloca
         }
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index fc0b9ff..3f3c5ac1 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -15,6 +15,7 @@
 use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types};
 use rustc::ty::{self, Ty};
 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};
@@ -81,13 +82,14 @@
 impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn codegen_intrinsic_call(
         &mut self,
-        callee_ty: Ty<'tcx>,
+        instance: ty::Instance<'tcx>,
         fn_ty: &FnType<'tcx, Ty<'tcx>>,
         args: &[OperandRef<'tcx, &'ll Value>],
         llresult: &'ll Value,
         span: Span,
     ) {
         let tcx = self.tcx;
+        let callee_ty = instance.ty(tcx);
 
         let (def_id, substs) = match callee_ty.sty {
             ty::FnDef(def_id, substs) => (def_id, substs),
@@ -133,10 +135,6 @@
                 let llfn = self.get_intrinsic(&("llvm.debugtrap"));
                 self.call(llfn, &[], None)
             }
-            "size_of" => {
-                let tp_ty = substs.type_at(0);
-                self.const_usize(self.size_of(tp_ty).bytes())
-            }
             "va_start" => {
                 self.va_start(args[0].immediate())
             }
@@ -188,10 +186,6 @@
                     self.const_usize(self.size_of(tp_ty).bytes())
                 }
             }
-            "min_align_of" => {
-                let tp_ty = substs.type_at(0);
-                self.const_usize(self.align_of(tp_ty).bytes())
-            }
             "min_align_of_val" => {
                 let tp_ty = substs.type_at(0);
                 if let OperandValue::Pair(_, meta) = args[0].val {
@@ -201,18 +195,19 @@
                     self.const_usize(self.align_of(tp_ty).bytes())
                 }
             }
-            "pref_align_of" => {
-                let tp_ty = substs.type_at(0);
-                self.const_usize(self.layout_of(tp_ty).align.pref.bytes())
-            }
+            "size_of" |
+            "pref_align_of" |
+            "min_align_of" |
+            "needs_drop" |
+            "type_id" |
             "type_name" => {
-                let tp_ty = substs.type_at(0);
-                let ty_name = self.tcx.type_name(tp_ty);
+                let gid = GlobalId {
+                    instance,
+                    promoted: None,
+                };
+                let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap();
                 OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
             }
-            "type_id" => {
-                self.const_u64(self.tcx.type_id_hash(substs.type_at(0)))
-            }
             "init" => {
                 let ty = substs.type_at(0);
                 if !self.layout_of(ty).is_zst() {
@@ -235,11 +230,6 @@
             "uninit" | "forget" => {
                 return;
             }
-            "needs_drop" => {
-                let tp_ty = substs.type_at(0);
-
-                self.const_bool(self.type_needs_drop(tp_ty))
-            }
             "offset" => {
                 let ptr = args[0].immediate();
                 let offset = args[1].immediate();
@@ -871,7 +861,7 @@
         // More information can be found in libstd's seh.rs implementation.
         let i64p = bx.type_ptr_to(bx.type_i64());
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let slot = bx.alloca(i64p, "slot", ptr_align);
+        let slot = bx.alloca(i64p, ptr_align);
         bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
 
         normal.ret(bx.const_i32(0));
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 9f2c303..34e39af 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -226,21 +226,21 @@
                 for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
                     println!("    {}", name);
                 }
-                println!("");
+                println!();
             }
             PrintRequest::CodeModels => {
                 println!("Available code models:");
                 for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
                     println!("    {}", name);
                 }
-                println!("");
+                println!();
             }
             PrintRequest::TlsModels => {
                 println!("Available TLS models:");
                 for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
                     println!("    {}", name);
                 }
-                println!("");
+                println!();
             }
             req => llvm_util::print(req, sess),
         }
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index 89a6ec2..bc028d6 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -17,8 +17,8 @@
 log = "0.4.5"
 libc = "0.2.44"
 jobserver = "0.1.11"
-parking_lot = "0.7"
-tempfile = "3.0.5"
+parking_lot = "0.9"
+tempfile = "3.1"
 
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_codegen_ssa/back/archive.rs b/src/librustc_codegen_ssa/back/archive.rs
index 23d580e..8d2120a 100644
--- a/src/librustc_codegen_ssa/back/archive.rs
+++ b/src/librustc_codegen_ssa/back/archive.rs
@@ -1,9 +1,10 @@
 use rustc::session::Session;
+use syntax::symbol::Symbol;
 
 use std::io;
 use std::path::{Path, PathBuf};
 
-pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session)
+pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session)
                     -> PathBuf {
     // On Windows, static libraries sometimes show up as libfoo.a and other
     // times show up as foo.lib
@@ -40,7 +41,7 @@
         lto: bool,
         skip_objects: bool,
     ) -> io::Result<()>;
-    fn add_native_library(&mut self, name: &str);
+    fn add_native_library(&mut self, name: Symbol);
     fn update_symbols(&mut self);
 
     fn build(self);
diff --git a/src/librustc_codegen_ssa/back/command.rs b/src/librustc_codegen_ssa/back/command.rs
index 340cc77..2d84d67 100644
--- a/src/librustc_codegen_ssa/back/command.rs
+++ b/src/librustc_codegen_ssa/back/command.rs
@@ -8,12 +8,14 @@
 use std::process::{self, Output};
 
 use rustc_target::spec::LldFlavor;
+use syntax::symbol::Symbol;
 
 #[derive(Clone)]
 pub struct Command {
     program: Program,
     args: Vec<OsString>,
     env: Vec<(OsString, OsString)>,
+    env_remove: Vec<OsString>,
 }
 
 #[derive(Clone)]
@@ -41,6 +43,7 @@
             program,
             args: Vec::new(),
             env: Vec::new(),
+            env_remove: Vec::new(),
         }
     }
 
@@ -49,6 +52,11 @@
         self
     }
 
+    pub fn sym_arg(&mut self, arg: Symbol) -> &mut Command {
+        self.arg(&arg.as_str());
+        self
+    }
+
     pub fn args<I>(&mut self, args: I) -> &mut Command
     where
         I: IntoIterator<Item: AsRef<OsStr>>,
@@ -75,6 +83,17 @@
         self.env.push((key.to_owned(), value.to_owned()));
     }
 
+    pub fn env_remove<K>(&mut self, key: K) -> &mut Command
+        where K: AsRef<OsStr>,
+    {
+        self._env_remove(key.as_ref());
+        self
+    }
+
+    fn _env_remove(&mut self, key: &OsStr) {
+        self.env_remove.push(key.to_owned());
+    }
+
     pub fn output(&mut self) -> io::Result<Output> {
         self.command().output()
     }
@@ -100,6 +119,9 @@
         };
         ret.args(&self.args);
         ret.envs(self.env.clone());
+        for k in &self.env_remove {
+            ret.env_remove(k);
+        }
         return ret
     }
 
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 8603d61..9b044d9 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -13,6 +13,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor};
+use syntax::symbol::Symbol;
 
 use crate::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION, CrateInfo, CodegenResults};
 use super::archive::ArchiveBuilder;
@@ -316,7 +317,7 @@
             NativeLibraryKind::NativeUnknown => continue,
         }
         if let Some(name) = lib.name {
-            ab.add_native_library(&name.as_str());
+            ab.add_native_library(name);
         }
     }
 
@@ -532,6 +533,9 @@
     for &(ref k, ref v) in &sess.target.target.options.link_env {
         cmd.env(k, v);
     }
+    for k in &sess.target.target.options.link_env_remove {
+        cmd.env_remove(k);
+    }
 
     if sess.opts.debugging_opts.print_link_args {
         println!("{:?}", &cmd);
@@ -1273,15 +1277,14 @@
     let search_path = archive_search_paths(sess);
     for lib in relevant_libs {
         let name = match lib.name {
-            Some(ref l) => l,
+            Some(l) => l,
             None => continue,
         };
         match lib.kind {
-            NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
-            NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
-            NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()),
-            NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(),
-                                                                        &search_path)
+            NativeLibraryKind::NativeUnknown => cmd.link_dylib(name),
+            NativeLibraryKind::NativeFramework => cmd.link_framework(name),
+            NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(name),
+            NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(name, &search_path)
         }
     }
 }
@@ -1594,7 +1597,7 @@
             cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
         }
         let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
-        cmd.link_rust_dylib(&unlib(&sess.target, filestem),
+        cmd.link_rust_dylib(Symbol::intern(&unlib(&sess.target, filestem)),
                             parent.unwrap_or(Path::new("")));
     }
 }
@@ -1637,22 +1640,22 @@
     for &(cnum, _) in crates {
         for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
             let name = match lib.name {
-                Some(ref l) => l,
+                Some(l) => l,
                 None => continue,
             };
             if !relevant_lib(sess, &lib) {
                 continue
             }
             match lib.kind {
-                NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
-                NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
+                NativeLibraryKind::NativeUnknown => cmd.link_dylib(name),
+                NativeLibraryKind::NativeFramework => cmd.link_framework(name),
                 NativeLibraryKind::NativeStaticNobundle => {
                     // Link "static-nobundle" native libs only if the crate they originate from
                     // is being linked statically to the current crate.  If it's linked dynamically
                     // or is an rlib already included via some other dylib crate, the symbols from
                     // native libs will have already been included in that dylib.
                     if data[cnum.as_usize() - 1] == Linkage::Static {
-                        cmd.link_staticlib(&name.as_str())
+                        cmd.link_staticlib(name)
                     }
                 },
                 // ignore statically included native libraries here as we've
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index de481d2..c42cd02 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -17,6 +17,7 @@
 use rustc::ty::TyCtxt;
 use rustc_target::spec::{LinkerFlavor, LldFlavor};
 use rustc_serialize::{json, Encoder};
+use syntax::symbol::Symbol;
 
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
@@ -99,13 +100,13 @@
 /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
 /// MSVC linker (e.g., `link.exe`) is being used.
 pub trait Linker {
-    fn link_dylib(&mut self, lib: &str);
-    fn link_rust_dylib(&mut self, lib: &str, path: &Path);
-    fn link_framework(&mut self, framework: &str);
-    fn link_staticlib(&mut self, lib: &str);
+    fn link_dylib(&mut self, lib: Symbol);
+    fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
+    fn link_framework(&mut self, framework: Symbol);
+    fn link_staticlib(&mut self, lib: Symbol);
     fn link_rlib(&mut self, lib: &Path);
     fn link_whole_rlib(&mut self, lib: &Path);
-    fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
+    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]);
     fn include_path(&mut self, path: &Path);
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
@@ -215,9 +216,13 @@
 }
 
 impl<'a> Linker for GccLinker<'a> {
-    fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); }
-    fn link_staticlib(&mut self, lib: &str) {
-        self.hint_static(); self.cmd.arg(format!("-l{}", lib));
+    fn link_dylib(&mut self, lib: Symbol) {
+        self.hint_dynamic();
+        self.cmd.arg(format!("-l{}", lib));
+    }
+    fn link_staticlib(&mut self, lib: Symbol) {
+        self.hint_static();
+        self.cmd.arg(format!("-l{}", lib));
     }
     fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
     fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
@@ -232,14 +237,14 @@
     fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
     fn args(&mut self, args: &[String]) { self.cmd.args(args); }
 
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
+    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
         self.hint_dynamic();
         self.cmd.arg(format!("-l{}", lib));
     }
 
-    fn link_framework(&mut self, framework: &str) {
+    fn link_framework(&mut self, framework: Symbol) {
         self.hint_dynamic();
-        self.cmd.arg("-framework").arg(framework);
+        self.cmd.arg("-framework").sym_arg(framework);
     }
 
     // Here we explicitly ask that the entire archive is included into the
@@ -248,7 +253,7 @@
     // don't otherwise explicitly reference them. This can occur for
     // libraries which are just providing bindings, libraries with generic
     // functions, etc.
-    fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
         self.hint_static();
         let target = &self.sess.target.target;
         if !target.options.is_like_osx {
@@ -539,11 +544,11 @@
         }
     }
 
-    fn link_dylib(&mut self, lib: &str) {
+    fn link_dylib(&mut self, lib: Symbol) {
         self.cmd.arg(&format!("{}.lib", lib));
     }
 
-    fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
+    fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
         // When producing a dll, the MSVC linker may not actually emit a
         // `foo.lib` file if the dll doesn't actually export any symbols, so we
         // check to see if the file is there and just omit linking to it if it's
@@ -554,7 +559,7 @@
         }
     }
 
-    fn link_staticlib(&mut self, lib: &str) {
+    fn link_staticlib(&mut self, lib: Symbol) {
         self.cmd.arg(&format!("{}.lib", lib));
     }
 
@@ -605,11 +610,11 @@
     fn framework_path(&mut self, _path: &Path) {
         bug!("frameworks are not supported on windows")
     }
-    fn link_framework(&mut self, _framework: &str) {
+    fn link_framework(&mut self, _framework: Symbol) {
         bug!("frameworks are not supported on windows")
     }
 
-    fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
         // not supported?
         self.link_staticlib(lib);
     }
@@ -740,8 +745,8 @@
         self.cmd.arg("-L").arg(path);
     }
 
-    fn link_staticlib(&mut self, lib: &str) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_staticlib(&mut self, lib: Symbol) {
+        self.cmd.arg("-l").sym_arg(lib);
     }
 
     fn output_filename(&mut self, path: &Path) {
@@ -752,12 +757,12 @@
         self.cmd.arg(path);
     }
 
-    fn link_dylib(&mut self, lib: &str) {
+    fn link_dylib(&mut self, lib: Symbol) {
         // Emscripten always links statically
         self.link_staticlib(lib);
     }
 
-    fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
         // not supported?
         self.link_staticlib(lib);
     }
@@ -767,7 +772,7 @@
         self.link_rlib(lib);
     }
 
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
+    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
         self.link_dylib(lib);
     }
 
@@ -803,7 +808,7 @@
         bug!("frameworks are not supported on Emscripten")
     }
 
-    fn link_framework(&mut self, _framework: &str) {
+    fn link_framework(&mut self, _framework: Symbol) {
         bug!("frameworks are not supported on Emscripten")
     }
 
@@ -948,12 +953,12 @@
 }
 
 impl<'a> Linker for WasmLd<'a> {
-    fn link_dylib(&mut self, lib: &str) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_dylib(&mut self, lib: Symbol) {
+        self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_staticlib(&mut self, lib: &str) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_staticlib(&mut self, lib: Symbol) {
+        self.cmd.arg("-l").sym_arg(lib);
     }
 
     fn link_rlib(&mut self, lib: &Path) {
@@ -995,16 +1000,16 @@
         self.cmd.args(args);
     }
 
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
+        self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_framework(&mut self, _framework: &str) {
+    fn link_framework(&mut self, _framework: Symbol) {
         panic!("frameworks not supported")
     }
 
-    fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
+        self.cmd.arg("-l").sym_arg(lib);
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
@@ -1162,19 +1167,19 @@
         ::std::mem::replace(&mut self.cmd, Command::new(""))
     }
 
-    fn link_dylib(&mut self, _lib: &str) {
+    fn link_dylib(&mut self, _lib: Symbol) {
         panic!("external dylibs not supported")
     }
 
-    fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
+    fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib(&mut self, _lib: &str) {
+    fn link_staticlib(&mut self, _lib: Symbol) {
         panic!("staticlibs not supported")
     }
 
-    fn link_whole_staticlib(&mut self, _lib: &str, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) {
         panic!("staticlibs not supported")
     }
 
@@ -1182,7 +1187,7 @@
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: &str) {
+    fn link_framework(&mut self, _framework: Symbol) {
         panic!("frameworks not supported")
     }
 
diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs
index 90bf964..1708d72 100644
--- a/src/librustc_codegen_ssa/lib.rs
+++ b/src/librustc_codegen_ssa/lib.rs
@@ -4,6 +4,7 @@
 #![feature(box_syntax)]
 #![feature(core_intrinsics)]
 #![feature(libc)]
+#![feature(slice_patterns)]
 #![feature(stmt_expr_attributes)]
 #![feature(try_blocks)]
 #![feature(in_band_lifetimes)]
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index e63f1b9..d192f2f 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -105,7 +105,7 @@
     ) {
         let cx = self.fx.cx;
 
-        if let Some(proj) = place_ref.projection {
+        if let [proj_base @ .., elem] = place_ref.projection {
             // Allow uses of projections that are ZSTs or from scalar fields.
             let is_consume = match context {
                 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
@@ -114,12 +114,12 @@
             };
             if is_consume {
                 let base_ty =
-                    mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx());
+                    mir::Place::ty_from(place_ref.base, proj_base, self.fx.mir, cx.tcx());
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
                 let elem_ty = base_ty
-                    .projection_ty(cx.tcx(), &proj.elem)
+                    .projection_ty(cx.tcx(), elem)
                     .ty;
                 let elem_ty = self.fx.monomorphize(&elem_ty);
                 let span = if let mir::PlaceBase::Local(index) = place_ref.base {
@@ -131,7 +131,7 @@
                     return;
                 }
 
-                if let mir::ProjectionElem::Field(..) = proj.elem {
+                if let mir::ProjectionElem::Field(..) = elem {
                     let layout = cx.spanned_layout_of(base_ty.ty, span);
                     if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
                         // Recurse with the same context, instead of `Projection`,
@@ -140,7 +140,7 @@
                         self.process_place(
                             &mir::PlaceRef {
                                 base: place_ref.base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             context,
                             location,
@@ -151,11 +151,11 @@
             }
 
             // A deref projection only reads the pointer, never needs the place.
-            if let mir::ProjectionElem::Deref = proj.elem {
+            if let mir::ProjectionElem::Deref = elem {
                 self.process_place(
                     &mir::PlaceRef {
                         base: place_ref.base,
-                        projection: &proj.base,
+                        projection: proj_base,
                     },
                     PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                     location
@@ -168,7 +168,7 @@
         // visit_place API
         let mut context = context;
 
-        if place_ref.projection.is_some() {
+        if !place_ref.projection.is_empty() {
             context = if context.is_mutating_use() {
                 PlaceContext::MutatingUse(MutatingUseContext::Projection)
             } else {
@@ -177,10 +177,7 @@
         }
 
         self.visit_place_base(place_ref.base, context, location);
-
-        if let Some(box proj) = place_ref.projection {
-            self.visit_projection(place_ref.base, proj, context, location);
-        }
+        self.visit_projection(place_ref.base, place_ref.projection, context, location);
     }
 
 }
@@ -196,7 +193,7 @@
 
         if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *place {
             self.assign(index, location);
             let decl_span = self.fx.mir.local_decls[index].source_info.span;
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index c41e463..1bb0ea5 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -253,7 +253,7 @@
 
             PassMode::Direct(_) | PassMode::Pair(..) => {
                 let op =
-                    self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_ref());
+                    self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref());
                 if let Ref(llval, _, align) = op.val {
                     bx.load(llval, align)
                 } else {
@@ -276,7 +276,7 @@
                 let llslot = match op.val {
                     Immediate(_) | Pair(..) => {
                         let scratch =
-                            PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout, "ret");
+                            PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout);
                         op.val.store(&mut bx, scratch);
                         scratch.llval
                     }
@@ -612,7 +612,7 @@
                                     ty,
                                     def_id: _,
                                 }),
-                                projection: None,
+                                projection: box [],
                             }
                         ) |
                         mir::Operand::Move(
@@ -622,7 +622,7 @@
                                     ty,
                                     def_id: _,
                                 }),
-                                projection: None,
+                                projection: box [],
                             }
                         ) => {
                             let param_env = ty::ParamEnv::reveal_all();
@@ -667,8 +667,7 @@
             }).collect();
 
 
-            let callee_ty = instance.as_ref().unwrap().ty(bx.tcx());
-            bx.codegen_intrinsic_call(callee_ty, &fn_ty, &args, dest,
+            bx.codegen_intrinsic_call(*instance.as_ref().unwrap(), &fn_ty, &args, dest,
                                       terminator.source_info.span);
 
             if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
@@ -767,7 +766,7 @@
             match (arg, op.val) {
                 (&mir::Operand::Copy(_), Ref(_, None, _)) |
                 (&mir::Operand::Constant(_), Ref(_, None, _)) => {
-                    let tmp = PlaceRef::alloca(&mut bx, op.layout, "const");
+                    let tmp = PlaceRef::alloca(&mut bx, op.layout);
                     op.val.store(&mut bx, tmp);
                     op.val = Ref(tmp.llval, None, tmp.align);
                 }
@@ -925,7 +924,7 @@
             Immediate(_) | Pair(..) => {
                 match arg.mode {
                     PassMode::Indirect(..) | PassMode::Cast(_) => {
-                        let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
+                        let scratch = PlaceRef::alloca(bx, arg.layout);
                         op.val.store(bx, scratch);
                         (scratch.llval, scratch.align, true)
                     }
@@ -940,7 +939,7 @@
                     // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
                     // have scary latent bugs around.
 
-                    let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
+                    let scratch = PlaceRef::alloca(bx, arg.layout);
                     base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align,
                                     op.layout, MemFlags::empty());
                     (scratch.llval, scratch.align, true)
@@ -1017,7 +1016,7 @@
                 cx.tcx().mk_mut_ptr(cx.tcx().types.u8),
                 cx.tcx().types.i32
             ]));
-            let slot = PlaceRef::alloca(bx, layout, "personalityslot");
+            let slot = PlaceRef::alloca(bx, layout);
             self.personality_slot = Some(slot);
             slot
         }
@@ -1105,7 +1104,7 @@
         }
         let dest = if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *dest {
             match self.locals[index] {
                 LocalRef::Place(dest) => dest,
@@ -1116,7 +1115,7 @@
                     return if fn_ret.is_indirect() {
                         // Odd, but possible, case, we have an operand temporary,
                         // but the calling convention has an indirect return.
-                        let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
+                        let tmp = PlaceRef::alloca(bx, fn_ret.layout);
                         tmp.storage_live(bx);
                         llargs.push(tmp.llval);
                         ReturnDest::IndirectOperand(tmp, index)
@@ -1124,7 +1123,7 @@
                         // Currently, intrinsics always need a location to store
                         // the result, so we create a temporary `alloca` for the
                         // result.
-                        let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
+                        let tmp = PlaceRef::alloca(bx, fn_ret.layout);
                         tmp.storage_live(bx);
                         ReturnDest::IndirectOperand(tmp, index)
                     } else {
@@ -1166,7 +1165,7 @@
     ) {
         if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *dst {
             match self.locals[index] {
                 LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
@@ -1174,7 +1173,7 @@
                 LocalRef::Operand(None) => {
                     let dst_layout = bx.layout_of(self.monomorphized_place_ty(&dst.as_ref()));
                     assert!(!dst_layout.ty.has_erasable_regions());
-                    let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
+                    let place = PlaceRef::alloca(bx, dst_layout);
                     place.storage_live(bx);
                     self.codegen_transmute_into(bx, src, place);
                     let op = bx.load_operand(place);
@@ -1227,7 +1226,7 @@
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
                 let op = if let PassMode::Cast(_) = ret_ty.mode {
-                    let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret");
+                    let tmp = PlaceRef::alloca(bx, ret_ty.layout);
                     tmp.storage_live(bx);
                     bx.store_arg_ty(&ret_ty, llval, tmp);
                     let op = bx.load_operand(tmp);
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index 00e9ca0..aa3971a 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -268,11 +268,13 @@
                 debug!("alloc: {:?} ({}) -> place", local, name);
                 if layout.is_unsized() {
                     let indirect_place =
-                        PlaceRef::alloca_unsized_indirect(&mut bx, layout, &name.as_str());
+                        PlaceRef::alloca_unsized_indirect(&mut bx, layout);
+                    bx.set_var_name(indirect_place.llval, name);
                     // FIXME: add an appropriate debuginfo
                     LocalRef::UnsizedPlace(indirect_place)
                 } else {
-                    let place = PlaceRef::alloca(&mut bx, layout, &name.as_str());
+                    let place = PlaceRef::alloca(&mut bx, layout);
+                    bx.set_var_name(place.llval, name);
                     if dbg {
                         let (scope, span) = fx.debug_loc(mir::SourceInfo {
                             span: decl.source_info.span,
@@ -293,14 +295,13 @@
                 } else if memory_locals.contains(local) {
                     debug!("alloc: {:?} -> place", local);
                     if layout.is_unsized() {
-                        let indirect_place = PlaceRef::alloca_unsized_indirect(
-                            &mut bx,
-                            layout,
-                            &format!("{:?}", local),
-                        );
+                        let indirect_place = PlaceRef::alloca_unsized_indirect(&mut bx, layout);
+                        bx.set_var_name(indirect_place.llval, format_args!("{:?}", local));
                         LocalRef::UnsizedPlace(indirect_place)
                     } else {
-                        LocalRef::Place(PlaceRef::alloca(&mut bx, layout, &format!("{:?}", local)))
+                        let place = PlaceRef::alloca(&mut bx, layout);
+                        bx.set_var_name(place.llval, format_args!("{:?}", local));
+                        LocalRef::Place(place)
                     }
                 } else {
                     // If this is an immediate local, we do not create an
@@ -452,10 +453,11 @@
     mir.args_iter().enumerate().map(|(arg_index, local)| {
         let arg_decl = &mir.local_decls[local];
 
+        // FIXME(eddyb) don't allocate a `String` unless it gets used.
         let name = if let Some(name) = arg_decl.name {
             name.as_str().to_string()
         } else {
-            format!("arg{}", arg_index)
+            format!("{:?}", local)
         };
 
         if Some(local) == mir.spread_arg {
@@ -470,7 +472,8 @@
                 _ => bug!("spread argument isn't a tuple?!")
             };
 
-            let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty), &name);
+            let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
+            bx.set_var_name(place.llval, name);
             for i in 0..tupled_arg_tys.len() {
                 let arg = &fx.fn_ty.args[idx];
                 idx += 1;
@@ -558,11 +561,13 @@
             llarg_idx += 1;
             let indirect_operand = OperandValue::Pair(llarg, llextra);
 
-            let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout, &name);
+            let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout);
+            bx.set_var_name(tmp.llval, name);
             indirect_operand.store(bx, tmp);
             tmp
         } else {
-            let tmp = PlaceRef::alloca(bx, arg.layout, &name);
+            let tmp = PlaceRef::alloca(bx, arg.layout);
+            bx.set_var_name(tmp.llval, name);
             if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) {
                 let va_list_did = match tcx.lang_items().va_list() {
                     Some(did) => did,
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index a8ab3ea..daa25b2 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -367,7 +367,7 @@
 
         // Allocate an appropriate region on the stack, and copy the value into it
         let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
-        let lldst = bx.array_alloca(bx.cx().type_i8(), llsize, "unsized_tmp", max_align);
+        let lldst = bx.array_alloca(bx.cx().type_i8(), llsize, max_align);
         bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags);
 
         // Store the allocated region and the extra to the indirect place.
@@ -384,47 +384,45 @@
     ) -> Option<OperandRef<'tcx, Bx::Value>> {
         debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
 
-        place_ref.iterate(|place_base, place_projection| {
-            if let mir::PlaceBase::Local(index) = place_base {
-                match self.locals[*index] {
-                    LocalRef::Operand(Some(mut o)) => {
-                        // Moves out of scalar and scalar pair fields are trivial.
-                        for proj in place_projection {
-                            match proj.elem {
-                                mir::ProjectionElem::Field(ref f, _) => {
-                                    o = o.extract_field(bx, f.index());
-                                }
-                                mir::ProjectionElem::Index(_) |
-                                mir::ProjectionElem::ConstantIndex { .. } => {
-                                    // ZSTs don't require any actual memory access.
-                                    // FIXME(eddyb) deduplicate this with the identical
-                                    // checks in `codegen_consume` and `extract_field`.
-                                    let elem = o.layout.field(bx.cx(), 0);
-                                    if elem.is_zst() {
-                                        o = OperandRef::new_zst(bx, elem);
-                                    } else {
-                                        return None;
-                                    }
-                                }
-                                _ => return None,
+        if let mir::PlaceBase::Local(index) = place_ref.base {
+            match self.locals[*index] {
+                LocalRef::Operand(Some(mut o)) => {
+                    // Moves out of scalar and scalar pair fields are trivial.
+                    for elem in place_ref.projection.iter() {
+                        match elem {
+                            mir::ProjectionElem::Field(ref f, _) => {
+                                o = o.extract_field(bx, f.index());
                             }
+                            mir::ProjectionElem::Index(_) |
+                            mir::ProjectionElem::ConstantIndex { .. } => {
+                                // ZSTs don't require any actual memory access.
+                                // FIXME(eddyb) deduplicate this with the identical
+                                // checks in `codegen_consume` and `extract_field`.
+                                let elem = o.layout.field(bx.cx(), 0);
+                                if elem.is_zst() {
+                                    o = OperandRef::new_zst(bx, elem);
+                                } else {
+                                    return None;
+                                }
+                            }
+                            _ => return None,
                         }
+                    }
 
-                        Some(o)
-                    }
-                    LocalRef::Operand(None) => {
-                        bug!("use of {:?} before def", place_ref);
-                    }
-                    LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
-                        // watch out for locals that do not have an
-                        // alloca; they are handled somewhat differently
-                        None
-                    }
+                    Some(o)
                 }
-            } else {
-                None
+                LocalRef::Operand(None) => {
+                    bug!("use of {:?} before def", place_ref);
+                }
+                LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
+                    // watch out for locals that do not have an
+                    // alloca; they are handled somewhat differently
+                    None
+                }
             }
-        })
+        } else {
+            None
+        }
     }
 
     pub fn codegen_consume(
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index b8e10d3..a4b4cb5 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -71,11 +71,9 @@
     pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         layout: TyLayout<'tcx>,
-        name: &str
     ) -> Self {
-        debug!("alloca({:?}: {:?})", name, layout);
         assert!(!layout.is_unsized(), "tried to statically allocate unsized place");
-        let tmp = bx.alloca(bx.cx().backend_type(layout), name, layout.align.abi);
+        let tmp = bx.alloca(bx.cx().backend_type(layout), layout.align.abi);
         Self::new_sized(tmp, layout)
     }
 
@@ -83,13 +81,11 @@
     pub fn alloca_unsized_indirect<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         layout: TyLayout<'tcx>,
-        name: &str,
     ) -> Self {
-        debug!("alloca_unsized_indirect({:?}: {:?})", name, layout);
         assert!(layout.is_unsized(), "tried to allocate indirect place for sized values");
         let ptr_ty = bx.cx().tcx().mk_mut_ptr(layout.ty);
         let ptr_layout = bx.cx().layout_of(ptr_ty);
-        Self::alloca(bx, ptr_layout, name)
+        Self::alloca(bx, ptr_layout)
     }
 
     pub fn len<Cx: ConstMethods<'tcx, Value = V>>(
@@ -449,7 +445,7 @@
         let result = match &place_ref {
             mir::PlaceRef {
                 base: mir::PlaceBase::Local(index),
-                projection: None,
+                projection: [],
             } => {
                 match self.locals[*index] {
                     LocalRef::Place(place) => {
@@ -469,7 +465,7 @@
                     kind: mir::StaticKind::Promoted(promoted, substs),
                     def_id,
                 }),
-                projection: None,
+                projection: [],
             } => {
                 let param_env = ty::ParamEnv::reveal_all();
                 let instance = Instance::new(*def_id, self.monomorphize(substs));
@@ -504,7 +500,7 @@
                     kind: mir::StaticKind::Static,
                     def_id,
                 }),
-                projection: None,
+                projection: [],
             } => {
                 // NB: The layout of a static may be unsized as is the case when working
                 // with a static that is an extern_type.
@@ -514,10 +510,7 @@
             },
             mir::PlaceRef {
                 base,
-                projection: Some(box mir::Projection {
-                    base: proj_base,
-                    elem: mir::ProjectionElem::Deref,
-                }),
+                projection: [proj_base @ .., mir::ProjectionElem::Deref],
             } => {
                 // Load the pointer from its location.
                 self.codegen_consume(bx, &mir::PlaceRef {
@@ -527,22 +520,22 @@
             }
             mir::PlaceRef {
                 base,
-                projection: Some(projection),
+                projection: [proj_base @ .., elem],
             } => {
                 // FIXME turn this recursion into iteration
                 let cg_base = self.codegen_place(bx, &mir::PlaceRef {
                     base,
-                    projection: &projection.base,
+                    projection: proj_base,
                 });
 
-                match projection.elem {
+                match elem {
                     mir::ProjectionElem::Deref => bug!(),
                     mir::ProjectionElem::Field(ref field, _) => {
                         cg_base.project_field(bx, field.index())
                     }
                     mir::ProjectionElem::Index(index) => {
                         let index = &mir::Operand::Copy(
-                            mir::Place::from(index)
+                            mir::Place::from(*index)
                         );
                         let index = self.codegen_operand(bx, index);
                         let llindex = index.immediate();
@@ -551,27 +544,27 @@
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: false,
                                                          min_length: _ } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
+                        let lloffset = bx.cx().const_usize(*offset as u64);
                         cg_base.project_index(bx, lloffset)
                     }
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: true,
                                                          min_length: _ } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
+                        let lloffset = bx.cx().const_usize(*offset as u64);
                         let lllen = cg_base.len(bx.cx());
                         let llindex = bx.sub(lllen, lloffset);
                         cg_base.project_index(bx, llindex)
                     }
                     mir::ProjectionElem::Subslice { from, to } => {
                         let mut subslice = cg_base.project_index(bx,
-                            bx.cx().const_usize(from as u64));
+                            bx.cx().const_usize(*from as u64));
                         let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
-                            .projection_ty(tcx, &projection.elem).ty;
+                            .projection_ty(tcx, elem).ty;
                         subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
 
                         if subslice.layout.is_unsized() {
                             subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
-                                bx.cx().const_usize((from as u64) + (to as u64))));
+                                bx.cx().const_usize((*from as u64) + (*to as u64))));
                         }
 
                         // Cast the place pointer type to the new
@@ -582,7 +575,7 @@
                         subslice
                     }
                     mir::ProjectionElem::Downcast(_, v) => {
-                        cg_base.project_downcast(bx, v)
+                        cg_base.project_downcast(bx, *v)
                     }
                 }
             }
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index e0ad252..f21836a 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -64,7 +64,7 @@
                         // index into the struct, and this case isn't
                         // important enough for it.
                         debug!("codegen_rvalue: creating ugly alloca");
-                        let scratch = PlaceRef::alloca(&mut bx, operand.layout, "__unsize_temp");
+                        let scratch = PlaceRef::alloca(&mut bx, operand.layout);
                         scratch.storage_live(&mut bx);
                         operand.val.store(&mut bx, scratch);
                         base::coerce_unsized_into(&mut bx, scratch, dest);
@@ -522,7 +522,7 @@
         // because codegen_place() panics if Local is operand.
         if let mir::Place {
             base: mir::PlaceBase::Local(index),
-            projection: None,
+            projection: box [],
         } = *place {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if let ty::Array(_, n) = op.layout.ty.sty {
diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs
index 594f45c..dab7dfc 100644
--- a/src/librustc_codegen_ssa/mir/statement.rs
+++ b/src/librustc_codegen_ssa/mir/statement.rs
@@ -16,12 +16,12 @@
 
         self.set_debug_loc(&mut bx, statement.source_info);
         match statement.kind {
-            mir::StatementKind::Assign(ref place, ref rvalue) => {
+            mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
                 if let mir::Place {
                     base: mir::PlaceBase::Local(index),
-                    projection: None,
-                } = *place {
-                    match self.locals[index] {
+                    projection: box [],
+                } = place {
+                    match self.locals[*index] {
                         LocalRef::Place(cg_dest) => {
                             self.codegen_rvalue(bx, cg_dest, rvalue)
                         }
@@ -30,7 +30,7 @@
                         }
                         LocalRef::Operand(None) => {
                             let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
-                            if let Some(name) = self.mir.local_decls[index].name {
+                            if let Some(name) = self.mir.local_decls[*index].name {
                                 match operand.val {
                                     OperandValue::Ref(x, ..) |
                                     OperandValue::Immediate(x) => {
@@ -44,7 +44,7 @@
                                     }
                                 }
                             }
-                            self.locals[index] = LocalRef::Operand(Some(operand));
+                            self.locals[*index] = LocalRef::Operand(Some(operand));
                             bx
                         }
                         LocalRef::Operand(Some(op)) => {
@@ -64,7 +64,7 @@
                     self.codegen_rvalue(bx, cg_dest, rvalue)
                 }
             }
-            mir::StatementKind::SetDiscriminant{ref place, variant_index} => {
+            mir::StatementKind::SetDiscriminant{box ref place, variant_index} => {
                 self.codegen_place(&mut bx, &place.as_ref())
                     .codegen_set_discr(&mut bx, variant_index);
                 bx
diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs
index 3a144f0..1886701 100644
--- a/src/librustc_codegen_ssa/traits/builder.rs
+++ b/src/librustc_codegen_ssa/traits/builder.rs
@@ -109,13 +109,12 @@
         rhs: Self::Value,
     ) -> (Self::Value, Self::Value);
 
-    fn alloca(&mut self, ty: Self::Type, name: &str, align: Align) -> Self::Value;
-    fn dynamic_alloca(&mut self, ty: Self::Type, name: &str, align: Align) -> Self::Value;
+    fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
+    fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
     fn array_alloca(
         &mut self,
         ty: Self::Type,
         len: Self::Value,
-        name: &str,
         align: Align,
     ) -> Self::Value;
 
diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs
index ede30a0..7c79cd6 100644
--- a/src/librustc_codegen_ssa/traits/intrinsic.rs
+++ b/src/librustc_codegen_ssa/traits/intrinsic.rs
@@ -1,6 +1,6 @@
 use super::BackendTypes;
 use crate::mir::operand::OperandRef;
-use rustc::ty::Ty;
+use rustc::ty::{self, Ty};
 use rustc_target::abi::call::FnType;
 use syntax_pos::Span;
 
@@ -10,7 +10,7 @@
     /// add them to librustc_codegen_llvm/context.rs
     fn codegen_intrinsic_call(
         &mut self,
-        callee_ty: Ty<'tcx>,
+        instance: ty::Instance<'tcx>,
         fn_ty: &FnType<'tcx, Ty<'tcx>>,
         args: &[OperandRef<'tcx, Self::Value>],
         llresult: Self::Value,
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 288676c..be9f79c 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -26,5 +26,5 @@
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 
 [dependencies.parking_lot]
-version = "0.7"
+version = "0.9"
 features = ["nightly"]
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 6f40d05..6e80b48 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -149,7 +149,7 @@
 
             #[inline]
             $v const unsafe fn from_u32_unchecked(value: u32) -> Self {
-                unsafe { $type { private: value } }
+                $type { private: value }
             }
 
             /// Extracts the value of this index as an integer.
diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs
index a0363e1..b2120b1 100644
--- a/src/librustc_data_structures/obligation_forest/graphviz.rs
+++ b/src/librustc_data_structures/obligation_forest/graphviz.rs
@@ -74,9 +74,9 @@
             .flat_map(|i| {
                 let node = &self.nodes[i];
 
-                node.parent.iter().map(|p| p.get())
-                    .chain(node.dependents.iter().map(|p| p.get()))
-                    .map(move |p| (p, i))
+                node.parent.iter()
+                    .chain(node.dependents.iter())
+                    .map(move |p| (p.index(), i))
             })
             .collect()
     }
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 04d2b23..189506b 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -9,7 +9,7 @@
 //! `ObligationForest` supports two main public operations (there are a
 //! few others not discussed here):
 //!
-//! 1. Add a new root obligations (`push_tree`).
+//! 1. Add a new root obligations (`register_obligation`).
 //! 2. Process the pending obligations (`process_obligations`).
 //!
 //! When a new obligation `N` is added, it becomes the root of an
@@ -20,13 +20,13 @@
 //! with every pending obligation (so that will include `N`, the first
 //! time). The callback also receives a (mutable) reference to the
 //! per-tree state `T`. The callback should process the obligation `O`
-//! that it is given and return one of three results:
+//! that it is given and return a `ProcessResult`:
 //!
-//! - `Ok(None)` -> ambiguous result. Obligation was neither a success
+//! - `Unchanged` -> ambiguous result. Obligation was neither a success
 //!   nor a failure. It is assumed that further attempts to process the
 //!   obligation will yield the same result unless something in the
 //!   surrounding environment changes.
-//! - `Ok(Some(C))` - the obligation was *shallowly successful*. The
+//! - `Changed(C)` - the obligation was *shallowly successful*. The
 //!   vector `C` is a list of subobligations. The meaning of this is that
 //!   `O` was successful on the assumption that all the obligations in `C`
 //!   are also successful. Therefore, `O` is only considered a "true"
@@ -34,7 +34,7 @@
 //!   state and the obligations in `C` become the new pending
 //!   obligations. They will be processed the next time you call
 //!   `process_obligations`.
-//! - `Err(E)` -> obligation failed with error `E`. We will collect this
+//! - `Error(E)` -> obligation failed with error `E`. We will collect this
 //!   error and return it from `process_obligations`, along with the
 //!   "backtrace" of obligations (that is, the list of obligations up to
 //!   and including the root of the failed obligation). No further
@@ -47,55 +47,50 @@
 //! - `completed`: a list of obligations where processing was fully
 //!   completed without error (meaning that all transitive subobligations
 //!   have also been completed). So, for example, if the callback from
-//!   `process_obligations` returns `Ok(Some(C))` for some obligation `O`,
+//!   `process_obligations` returns `Changed(C)` for some obligation `O`,
 //!   then `O` will be considered completed right away if `C` is the
 //!   empty vector. Otherwise it will only be considered completed once
 //!   all the obligations in `C` have been found completed.
 //! - `errors`: a list of errors that occurred and associated backtraces
 //!   at the time of error, which can be used to give context to the user.
 //! - `stalled`: if true, then none of the existing obligations were
-//!   *shallowly successful* (that is, no callback returned `Ok(Some(_))`).
+//!   *shallowly successful* (that is, no callback returned `Changed(_)`).
 //!   This implies that all obligations were either errors or returned an
 //!   ambiguous result, which means that any further calls to
 //!   `process_obligations` would simply yield back further ambiguous
 //!   results. This is used by the `FulfillmentContext` to decide when it
 //!   has reached a steady state.
 //!
-//! #### Snapshots
-//!
-//! The `ObligationForest` supports a limited form of snapshots; see
-//! `start_snapshot`, `commit_snapshot`, and `rollback_snapshot`. In
-//! particular, you can use a snapshot to roll back new root
-//! obligations. However, it is an error to attempt to
-//! `process_obligations` during a snapshot.
-//!
 //! ### Implementation details
 //!
 //! For the most part, comments specific to the implementation are in the
 //! code. This file only contains a very high-level overview. Basically,
 //! the forest is stored in a vector. Each element of the vector is a node
-//! in some tree. Each node in the vector has the index of an (optional)
-//! parent and (for convenience) its root (which may be itself). It also
-//! has a current state, described by `NodeState`. After each
-//! processing step, we compress the vector to remove completed and error
-//! nodes, which aren't needed anymore.
+//! in some tree. Each node in the vector has the index of its dependents,
+//! including the first dependent which is known as the parent. It also
+//! has a current state, described by `NodeState`. After each processing
+//! step, we compress the vector to remove completed and error nodes, which
+//! aren't needed anymore.
 
 use crate::fx::{FxHashMap, FxHashSet};
+use crate::indexed_vec::Idx;
+use crate::newtype_index;
 
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash;
 use std::marker::PhantomData;
 
-mod node_index;
-use self::node_index::NodeIndex;
-
 mod graphviz;
 
 #[cfg(test)]
 mod tests;
 
+newtype_index! {
+    pub struct NodeIndex { .. }
+}
+
 pub trait ForestObligation : Clone + Debug {
     type Predicate : Clone + hash::Hash + Eq + Debug;
 
@@ -148,18 +143,22 @@
     /// At the end of processing, those nodes will be removed by a
     /// call to `compress`.
     ///
-    /// At all times we maintain the invariant that every node appears
-    /// at a higher index than its parent. This is needed by the
-    /// backtrace iterator (which uses `split_at`).
+    /// Ideally, this would be an `IndexVec<NodeIndex, Node<O>>`. But that is
+    /// slower, because this vector is accessed so often that the
+    /// `u32`-to-`usize` conversions required for accesses are significant.
     nodes: Vec<Node<O>>,
 
     /// A cache of predicates that have been successfully completed.
     done_cache: FxHashSet<O::Predicate>,
 
-    /// An cache of the nodes in `nodes`, indexed by predicate.
+    /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately,
+    /// its contents are not guaranteed to match those of `nodes`. See the
+    /// comments in `process_obligation` for details.
     waiting_cache: FxHashMap<O::Predicate, NodeIndex>,
 
-    scratch: Option<Vec<usize>>,
+    /// A scratch vector reused in various operations, to avoid allocating new
+    /// vectors.
+    scratch: RefCell<Vec<usize>>,
 
     obligation_tree_id_generator: ObligationTreeIdGenerator,
 
@@ -178,19 +177,41 @@
     obligation: O,
     state: Cell<NodeState>,
 
-    /// The parent of a node - the original obligation of
-    /// which it is a subobligation. Except for error reporting,
-    /// it is just like any member of `dependents`.
+    /// The parent of a node - the original obligation of which it is a
+    /// subobligation. Except for error reporting, it is just like any member
+    /// of `dependents`.
+    ///
+    /// Unlike `ObligationForest::nodes`, this uses `NodeIndex` rather than
+    /// `usize` for the index, because keeping the size down is more important
+    /// than the cost of converting to a `usize` for indexing.
     parent: Option<NodeIndex>,
 
-    /// Obligations that depend on this obligation for their
-    /// completion. They must all be in a non-pending state.
+    /// Obligations that depend on this obligation for their completion. They
+    /// must all be in a non-pending state.
+    ///
+    /// This uses `NodeIndex` for the same reason as `parent`.
     dependents: Vec<NodeIndex>,
 
     /// Identifier of the obligation tree to which this node belongs.
     obligation_tree_id: ObligationTreeId,
 }
 
+impl<O> Node<O> {
+    fn new(
+        parent: Option<NodeIndex>,
+        obligation: O,
+        obligation_tree_id: ObligationTreeId
+    ) -> Node<O> {
+        Node {
+            obligation,
+            state: Cell::new(NodeState::Pending),
+            parent,
+            dependents: vec![],
+            obligation_tree_id,
+        }
+    }
+}
+
 /// The state of one node in some tree within the forest. This
 /// represents the current state of processing for the obligation (of
 /// type `O`) associated with this node.
@@ -262,7 +283,7 @@
             nodes: vec![],
             done_cache: Default::default(),
             waiting_cache: Default::default(),
-            scratch: Some(vec![]),
+            scratch: RefCell::new(vec![]),
             obligation_tree_id_generator: (0..).map(ObligationTreeId),
             error_cache: Default::default(),
         }
@@ -275,14 +296,12 @@
     }
 
     /// Registers an obligation.
-    ///
-    /// This CAN be done in a snapshot
     pub fn register_obligation(&mut self, obligation: O) {
         // Ignore errors here - there is no guarantee of success.
         let _ = self.register_obligation_at(obligation, None);
     }
 
-    // returns Err(()) if we already know this obligation failed.
+    // Returns Err(()) if we already know this obligation failed.
     fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>)
                               -> Result<(), ()>
     {
@@ -294,15 +313,16 @@
             Entry::Occupied(o) => {
                 debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
                        obligation, parent, o.get());
-                let node = &mut self.nodes[o.get().get()];
-                if let Some(parent) = parent {
+                let node = &mut self.nodes[o.get().index()];
+                if let Some(parent_index) = parent {
                     // If the node is already in `waiting_cache`, it's already
                     // been marked with a parent. (It's possible that parent
                     // has been cleared by `apply_rewrites`, though.) So just
                     // dump `parent` into `node.dependents`... unless it's
                     // already in `node.dependents` or `node.parent`.
-                    if !node.dependents.contains(&parent) && Some(parent) != node.parent {
-                        node.dependents.push(parent);
+                    if !node.dependents.contains(&parent_index) &&
+                       Some(parent_index) != node.parent {
+                        node.dependents.push(parent_index);
                     }
                 }
                 if let NodeState::Error = node.state.get() {
@@ -316,9 +336,8 @@
                        obligation, parent, self.nodes.len());
 
                 let obligation_tree_id = match parent {
-                    Some(p) => {
-                        let parent_node = &self.nodes[p.get()];
-                        parent_node.obligation_tree_id
+                    Some(parent_index) => {
+                        self.nodes[parent_index.index()].obligation_tree_id
                     }
                     None => self.obligation_tree_id_generator.next().unwrap()
                 };
@@ -342,13 +361,11 @@
     }
 
     /// Converts all remaining obligations to the given error.
-    ///
-    /// This cannot be done during a snapshot.
     pub fn to_errors<E: Clone>(&mut self, error: E) -> Vec<Error<O, E>> {
         let mut errors = vec![];
-        for index in 0..self.nodes.len() {
-            if let NodeState::Pending = self.nodes[index].state.get() {
-                let backtrace = self.error_at(index);
+        for (i, node) in self.nodes.iter().enumerate() {
+            if let NodeState::Pending = node.state.get() {
+                let backtrace = self.error_at(i);
                 errors.push(Error {
                     error: error.clone(),
                     backtrace,
@@ -373,7 +390,6 @@
 
     fn insert_into_error_cache(&mut self, node_index: usize) {
         let node = &self.nodes[node_index];
-
         self.error_cache
             .entry(node.obligation_tree_id)
             .or_default()
@@ -393,16 +409,22 @@
         let mut errors = vec![];
         let mut stalled = true;
 
-        for index in 0..self.nodes.len() {
-            debug!("process_obligations: node {} == {:?}", index, self.nodes[index]);
+        for i in 0..self.nodes.len() {
+            let node = &mut self.nodes[i];
 
-            let result = match self.nodes[index] {
-                Node { ref state, ref mut obligation, .. } if state.get() == NodeState::Pending =>
-                    processor.process_obligation(obligation),
+            debug!("process_obligations: node {} == {:?}", i, node);
+
+            // `processor.process_obligation` can modify the predicate within
+            // `node.obligation`, and that predicate is the key used for
+            // `self.waiting_cache`. This means that `self.waiting_cache` can
+            // get out of sync with `nodes`. It's not very common, but it does
+            // happen, and code in `compress` has to allow for it.
+            let result = match node.state.get() {
+                NodeState::Pending => processor.process_obligation(&mut node.obligation),
                 _ => continue
             };
 
-            debug!("process_obligations: node {} got result {:?}", index, result);
+            debug!("process_obligations: node {} got result {:?}", i, result);
 
             match result {
                 ProcessResult::Unchanged => {
@@ -411,23 +433,23 @@
                 ProcessResult::Changed(children) => {
                     // We are not (yet) stalled.
                     stalled = false;
-                    self.nodes[index].state.set(NodeState::Success);
+                    node.state.set(NodeState::Success);
 
                     for child in children {
                         let st = self.register_obligation_at(
                             child,
-                            Some(NodeIndex::new(index))
+                            Some(NodeIndex::new(i))
                         );
                         if let Err(()) = st {
-                            // error already reported - propagate it
+                            // Error already reported - propagate it
                             // to our node.
-                            self.error_at(index);
+                            self.error_at(i);
                         }
                     }
                 }
                 ProcessResult::Error(err) => {
                     stalled = false;
-                    let backtrace = self.error_at(index);
+                    let backtrace = self.error_at(i);
                     errors.push(Error {
                         error: err,
                         backtrace,
@@ -448,8 +470,6 @@
 
         self.mark_as_waiting();
         self.process_cycles(processor);
-
-        // Now we have to compress the result
         let completed = self.compress(do_completed);
 
         debug!("process_obligations: complete");
@@ -465,107 +485,109 @@
     /// report all cycles between them. This should be called
     /// after `mark_as_waiting` marks all nodes with pending
     /// subobligations as NodeState::Waiting.
-    fn process_cycles<P>(&mut self, processor: &mut P)
+    fn process_cycles<P>(&self, processor: &mut P)
         where P: ObligationProcessor<Obligation=O>
     {
-        let mut stack = self.scratch.take().unwrap();
+        let mut stack = self.scratch.replace(vec![]);
         debug_assert!(stack.is_empty());
 
         debug!("process_cycles()");
 
-        for index in 0..self.nodes.len() {
+        for (i, node) in self.nodes.iter().enumerate() {
             // For rustc-benchmarks/inflate-0.1.0 this state test is extremely
             // hot and the state is almost always `Pending` or `Waiting`. It's
             // a win to handle the no-op cases immediately to avoid the cost of
             // the function call.
-            let state = self.nodes[index].state.get();
-            match state {
+            match node.state.get() {
                 NodeState::Waiting | NodeState::Pending | NodeState::Done | NodeState::Error => {},
-                _ => self.find_cycles_from_node(&mut stack, processor, index),
+                _ => self.find_cycles_from_node(&mut stack, processor, i),
             }
         }
 
         debug!("process_cycles: complete");
 
         debug_assert!(stack.is_empty());
-        self.scratch = Some(stack);
+        self.scratch.replace(stack);
     }
 
-    fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>,
-                                processor: &mut P, index: usize)
+    fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, i: usize)
         where P: ObligationProcessor<Obligation=O>
     {
-        let node = &self.nodes[index];
-        let state = node.state.get();
-        match state {
+        let node = &self.nodes[i];
+        match node.state.get() {
             NodeState::OnDfsStack => {
-                let index =
-                    stack.iter().rposition(|n| *n == index).unwrap();
-                processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)),
+                let i = stack.iter().rposition(|n| *n == i).unwrap();
+                processor.process_backedge(stack[i..].iter().map(GetObligation(&self.nodes)),
                                            PhantomData);
             }
             NodeState::Success => {
                 node.state.set(NodeState::OnDfsStack);
-                stack.push(index);
-                for dependent in node.parent.iter().chain(node.dependents.iter()) {
-                    self.find_cycles_from_node(stack, processor, dependent.get());
+                stack.push(i);
+                for index in node.parent.iter().chain(node.dependents.iter()) {
+                    self.find_cycles_from_node(stack, processor, index.index());
                 }
                 stack.pop();
                 node.state.set(NodeState::Done);
             },
             NodeState::Waiting | NodeState::Pending => {
-                // this node is still reachable from some pending node. We
+                // This node is still reachable from some pending node. We
                 // will get to it when they are all processed.
             }
             NodeState::Done | NodeState::Error => {
-                // already processed that node
+                // Already processed that node.
             }
         };
     }
 
     /// Returns a vector of obligations for `p` and all of its
     /// ancestors, putting them into the error state in the process.
-    fn error_at(&mut self, p: usize) -> Vec<O> {
-        let mut error_stack = self.scratch.take().unwrap();
+    fn error_at(&self, mut i: usize) -> Vec<O> {
+        let mut error_stack = self.scratch.replace(vec![]);
         let mut trace = vec![];
 
-        let mut n = p;
         loop {
-            self.nodes[n].state.set(NodeState::Error);
-            trace.push(self.nodes[n].obligation.clone());
-            error_stack.extend(self.nodes[n].dependents.iter().map(|x| x.get()));
+            let node = &self.nodes[i];
+            node.state.set(NodeState::Error);
+            trace.push(node.obligation.clone());
+            error_stack.extend(node.dependents.iter().map(|index| index.index()));
 
-            // loop to the parent
-            match self.nodes[n].parent {
-                Some(q) => n = q.get(),
+            // Loop to the parent.
+            match node.parent {
+                Some(parent_index) => i = parent_index.index(),
                 None => break
             }
         }
 
         while let Some(i) = error_stack.pop() {
-            match self.nodes[i].state.get() {
+            let node = &self.nodes[i];
+            match node.state.get() {
                 NodeState::Error => continue,
-                _ => self.nodes[i].state.set(NodeState::Error),
+                _ => node.state.set(NodeState::Error),
             }
 
-            let node = &self.nodes[i];
-
             error_stack.extend(
-                node.parent.iter().chain(node.dependents.iter()).map(|x| x.get())
+                node.parent.iter().chain(node.dependents.iter()).map(|index| index.index())
             );
         }
 
-        self.scratch = Some(error_stack);
+        self.scratch.replace(error_stack);
         trace
     }
 
-    #[inline]
-    fn mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
+    // This always-inlined function is for the hot call site.
+    #[inline(always)]
+    fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
         for dependent in node.parent.iter().chain(node.dependents.iter()) {
-            self.mark_as_waiting_from(&self.nodes[dependent.get()]);
+            self.mark_as_waiting_from(&self.nodes[dependent.index()]);
         }
     }
 
+    // This never-inlined function is for the cold call site.
+    #[inline(never)]
+    fn uninlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
+        self.inlined_mark_neighbors_as_waiting_from(node)
+    }
+
     /// Marks all nodes that depend on a pending node as `NodeState::Waiting`.
     fn mark_as_waiting(&self) {
         for node in &self.nodes {
@@ -576,7 +598,8 @@
 
         for node in &self.nodes {
             if node.state.get() == NodeState::Pending {
-                self.mark_neighbors_as_waiting_from(node);
+                // This call site is hot.
+                self.inlined_mark_neighbors_as_waiting_from(node);
             }
         }
     }
@@ -588,7 +611,8 @@
             NodeState::Pending | NodeState::Done => {},
         }
 
-        self.mark_neighbors_as_waiting_from(node);
+        // This call site is cold.
+        self.uninlined_mark_neighbors_as_waiting_from(node);
     }
 
     /// Compresses the vector, removing all popped nodes. This adjusts
@@ -600,7 +624,7 @@
     #[inline(never)]
     fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
         let nodes_len = self.nodes.len();
-        let mut node_rewrites: Vec<_> = self.scratch.take().unwrap();
+        let mut node_rewrites: Vec<_> = self.scratch.replace(vec![]);
         node_rewrites.extend(0..nodes_len);
         let mut dead_nodes = 0;
 
@@ -611,7 +635,8 @@
         //     self.nodes[i - dead_nodes..i] are all dead
         //     self.nodes[i..] are unchanged
         for i in 0..self.nodes.len() {
-            match self.nodes[i].state.get() {
+            let node = &self.nodes[i];
+            match node.state.get() {
                 NodeState::Pending | NodeState::Waiting => {
                     if dead_nodes > 0 {
                         self.nodes.swap(i, i - dead_nodes);
@@ -619,13 +644,16 @@
                     }
                 }
                 NodeState::Done => {
-                    // Avoid cloning the key (predicate) in case it exists in the waiting cache
+                    // This lookup can fail because the contents of
+                    // `self.waiting_cache` is not guaranteed to match those of
+                    // `self.nodes`. See the comment in `process_obligation`
+                    // for more details.
                     if let Some((predicate, _)) = self.waiting_cache
-                        .remove_entry(self.nodes[i].obligation.as_predicate())
+                        .remove_entry(node.obligation.as_predicate())
                     {
                         self.done_cache.insert(predicate);
                     } else {
-                        self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone());
+                        self.done_cache.insert(node.obligation.as_predicate().clone());
                     }
                     node_rewrites[i] = nodes_len;
                     dead_nodes += 1;
@@ -634,7 +662,7 @@
                     // We *intentionally* remove the node from the cache at this point. Otherwise
                     // tests must come up with a different type on every type error they
                     // check against.
-                    self.waiting_cache.remove(self.nodes[i].obligation.as_predicate());
+                    self.waiting_cache.remove(node.obligation.as_predicate());
                     node_rewrites[i] = nodes_len;
                     dead_nodes += 1;
                     self.insert_into_error_cache(i);
@@ -646,12 +674,11 @@
         // No compression needed.
         if dead_nodes == 0 {
             node_rewrites.truncate(0);
-            self.scratch = Some(node_rewrites);
+            self.scratch.replace(node_rewrites);
             return if do_completed == DoCompleted::Yes { Some(vec![]) } else { None };
         }
 
-        // Pop off all the nodes we killed and extract the success
-        // stories.
+        // Pop off all the nodes we killed and extract the success stories.
         let successful = if do_completed == DoCompleted::Yes {
             Some((0..dead_nodes)
                 .map(|_| self.nodes.pop().unwrap())
@@ -670,7 +697,7 @@
         self.apply_rewrites(&node_rewrites);
 
         node_rewrites.truncate(0);
-        self.scratch = Some(node_rewrites);
+        self.scratch.replace(node_rewrites);
 
         successful
     }
@@ -680,58 +707,41 @@
 
         for node in &mut self.nodes {
             if let Some(index) = node.parent {
-                let new_index = node_rewrites[index.get()];
-                if new_index >= nodes_len {
-                    // parent dead due to error
+                let new_i = node_rewrites[index.index()];
+                if new_i >= nodes_len {
                     node.parent = None;
                 } else {
-                    node.parent = Some(NodeIndex::new(new_index));
+                    node.parent = Some(NodeIndex::new(new_i));
                 }
             }
 
             let mut i = 0;
             while i < node.dependents.len() {
-                let new_index = node_rewrites[node.dependents[i].get()];
-                if new_index >= nodes_len {
+                let new_i = node_rewrites[node.dependents[i].index()];
+                if new_i >= nodes_len {
                     node.dependents.swap_remove(i);
                 } else {
-                    node.dependents[i] = NodeIndex::new(new_index);
+                    node.dependents[i] = NodeIndex::new(new_i);
                     i += 1;
                 }
             }
         }
 
-        let mut kill_list = vec![];
-        for (predicate, index) in &mut self.waiting_cache {
-            let new_index = node_rewrites[index.get()];
-            if new_index >= nodes_len {
-                kill_list.push(predicate.clone());
+        // This updating of `self.waiting_cache` is necessary because the
+        // removal of nodes within `compress` can fail. See above.
+        self.waiting_cache.retain(|_predicate, index| {
+            let new_i = node_rewrites[index.index()];
+            if new_i >= nodes_len {
+                false
             } else {
-                *index = NodeIndex::new(new_index);
+                *index = NodeIndex::new(new_i);
+                true
             }
-        }
-
-        for predicate in kill_list { self.waiting_cache.remove(&predicate); }
+        });
     }
 }
 
-impl<O> Node<O> {
-    fn new(
-        parent: Option<NodeIndex>,
-        obligation: O,
-        obligation_tree_id: ObligationTreeId
-    ) -> Node<O> {
-        Node {
-            obligation,
-            state: Cell::new(NodeState::Pending),
-            parent,
-            dependents: vec![],
-            obligation_tree_id,
-        }
-    }
-}
-
-// I need a Clone closure
+// I need a Clone closure.
 #[derive(Clone)]
 struct GetObligation<'a, O>(&'a [Node<O>]);
 
diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs
deleted file mode 100644
index 69ea473..0000000
--- a/src/librustc_data_structures/obligation_forest/node_index.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::num::NonZeroU32;
-use std::u32;
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct NodeIndex {
-    index: NonZeroU32,
-}
-
-impl NodeIndex {
-    #[inline]
-    pub fn new(value: usize) -> NodeIndex {
-        assert!(value < (u32::MAX as usize));
-        NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() }
-    }
-
-    #[inline]
-    pub fn get(self) -> usize {
-        (self.index.get() - 1) as usize
-    }
-}
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index a839ee5..25f67b3 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -11,6 +11,7 @@
 
 [dependencies]
 graphviz = { path = "../libgraphviz" }
+lazy_static = "1.0"
 log = "0.4"
 env_logger = { version = "0.6", default-features = false }
 rustc = { path = "../librustc" }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index a912ea3..8c5d853 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -20,6 +20,8 @@
 extern crate libc;
 #[macro_use]
 extern crate log;
+#[macro_use]
+extern crate lazy_static;
 
 pub extern crate rustc_plugin_impl as plugin;
 
@@ -35,8 +37,8 @@
 use rustc::lint::Lint;
 use rustc::lint;
 use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::util::common::{ErrorReported, install_panic_hook, print_time_passes_entry};
-use rustc::util::common::{set_time_depth, time};
+use rustc::ty::TyCtxt;
+use rustc::util::common::{set_time_depth, time, print_time_passes_entry, ErrorReported};
 use rustc_metadata::locator;
 use rustc_metadata::cstore::CStore;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
@@ -132,8 +134,11 @@
 
 impl Callbacks for TimePassesCallbacks {
     fn config(&mut self, config: &mut interface::Config) {
+        // If a --prints=... option has been given, we don't print the "total"
+        // time because it will mess up the --prints output. See #64339.
         self.time_passes =
-            config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time;
+            config.opts.prints.is_empty() &&
+            (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
     }
 }
 
@@ -161,8 +166,6 @@
         None => return Ok(()),
     };
 
-    install_panic_hook();
-
     let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
 
     let mut dummy_config = |sopts, cfg, diagnostic_output| {
@@ -1151,63 +1154,107 @@
     }
 }
 
-/// Runs a procedure which will detect panics in the compiler and print nicer
-/// error messages rather than just failing the test.
+/// Runs a closure and catches unwinds triggered by fatal errors.
 ///
-/// The diagnostic emitter yielded to the procedure should be used for reporting
-/// errors of the compiler.
-pub fn report_ices_to_stderr_if_any<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
+/// The compiler currently unwinds with a special sentinel value to abort
+/// compilation on fatal errors. This function catches that sentinel and turns
+/// the panic into a `Result` instead.
+pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
     catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
         if value.is::<errors::FatalErrorMarker>() {
             ErrorReported
         } else {
-            // Thread panicked without emitting a fatal diagnostic
-            eprintln!("");
-
-            let emitter = Box::new(errors::emitter::EmitterWriter::stderr(
-                errors::ColorConfig::Auto,
-                None,
-                false,
-                false,
-                None,
-            ));
-            let handler = errors::Handler::with_emitter(true, None, emitter);
-
-            // a .span_bug or .bug call has already printed what
-            // it wants to print.
-            if !value.is::<errors::ExplicitBug>() {
-                handler.emit(&MultiSpan::new(),
-                             "unexpected panic",
-                             errors::Level::Bug);
-            }
-
-            let mut xs: Vec<Cow<'static, str>> = vec![
-                "the compiler unexpectedly panicked. this is a bug.".into(),
-                format!("we would appreciate a bug report: {}", BUG_REPORT_URL).into(),
-                format!("rustc {} running on {}",
-                        option_env!("CFG_VERSION").unwrap_or("unknown_version"),
-                        config::host_triple()).into(),
-            ];
-
-            if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
-                xs.push(format!("compiler flags: {}", flags.join(" ")).into());
-
-                if excluded_cargo_defaults {
-                    xs.push("some of the compiler flags provided by cargo are hidden".into());
-                }
-            }
-
-            for note in &xs {
-                handler.emit(&MultiSpan::new(),
-                             note,
-                             errors::Level::Note);
-            }
-
-            panic::resume_unwind(Box::new(errors::FatalErrorMarker));
+            panic::resume_unwind(value);
         }
     })
 }
 
+lazy_static! {
+    static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
+        let hook = panic::take_hook();
+        panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL)));
+        hook
+    };
+}
+
+/// Prints the ICE message, including backtrace and query stack.
+///
+/// The message will point the user at `bug_report_url` to report the ICE.
+///
+/// When `install_ice_hook` is called, this function will be called as the panic
+/// hook.
+pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
+    // Invoke the default handler, which prints the actual panic message and optionally a backtrace
+    (*DEFAULT_HOOK)(info);
+
+    // Separate the output with an empty line
+    eprintln!();
+
+    let emitter = Box::new(errors::emitter::EmitterWriter::stderr(
+        errors::ColorConfig::Auto,
+        None,
+        false,
+        false,
+        None,
+    ));
+    let handler = errors::Handler::with_emitter(true, None, emitter);
+
+    // a .span_bug or .bug call has already printed what
+    // it wants to print.
+    if !info.payload().is::<errors::ExplicitBug>() {
+        handler.emit(&MultiSpan::new(),
+                     "unexpected panic",
+                     errors::Level::Bug);
+    }
+
+    let mut xs: Vec<Cow<'static, str>> = vec![
+        "the compiler unexpectedly panicked. this is a bug.".into(),
+        format!("we would appreciate a bug report: {}", bug_report_url).into(),
+        format!("rustc {} running on {}",
+                option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+                config::host_triple()).into(),
+    ];
+
+    if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
+        xs.push(format!("compiler flags: {}", flags.join(" ")).into());
+
+        if excluded_cargo_defaults {
+            xs.push("some of the compiler flags provided by cargo are hidden".into());
+        }
+    }
+
+    for note in &xs {
+        handler.emit(&MultiSpan::new(),
+                     note,
+                     errors::Level::Note);
+    }
+
+    // If backtraces are enabled, also print the query stack
+    let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
+
+    if backtrace {
+        TyCtxt::try_print_query_stack();
+    }
+
+    #[cfg(windows)]
+    unsafe {
+        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
+            extern "system" {
+                fn DebugBreak();
+            }
+            // Trigger a debugger if we crashed during bootstrap
+            DebugBreak();
+        }
+    }
+}
+
+/// Installs a panic hook that will print the ICE message on unexpected panics.
+///
+/// A custom rustc driver can skip calling this to set up a custom ICE hook.
+pub fn install_ice_hook() {
+    lazy_static::initialize(&DEFAULT_HOOK);
+}
+
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// log crate version
 pub fn init_rustc_env_logger() {
@@ -1218,7 +1265,8 @@
     let start = Instant::now();
     init_rustc_env_logger();
     let mut callbacks = TimePassesCallbacks::default();
-    let result = report_ices_to_stderr_if_any(|| {
+    install_ice_hook();
+    let result = catch_fatal_errors(|| {
         let args = env::args_os().enumerate()
             .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
                     early_error(ErrorOutputType::default(),
diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs
index 39b9061..c626dd0 100644
--- a/src/librustc_errors/annotate_snippet_emitter_writer.rs
+++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs
@@ -37,7 +37,7 @@
                                           &mut primary_span,
                                           &mut children,
                                           &db.level,
-                                          db.handler.flags.external_macro_backtrace);
+                                          db.handler().flags.external_macro_backtrace);
 
         self.emit_messages_default(&db.level,
                                    db.message(),
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 41d0638..7b8902f 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -18,8 +18,17 @@
 /// extending `HandlerFlags`, accessed via `self.handler.flags`.
 #[must_use]
 #[derive(Clone)]
-pub struct DiagnosticBuilder<'a> {
-    pub handler: &'a Handler,
+pub struct DiagnosticBuilder<'a>(Box<DiagnosticBuilderInner<'a>>);
+
+/// This is a large type, and often used as a return value, especially within
+/// the frequently-used `PResult` type. In theory, return value optimization
+/// (RVO) should avoid unnecessary copying. In practice, it does not (at the
+/// time of writing). The split between `DiagnosticBuilder` and
+/// `DiagnosticBuilderInner` exists to avoid many `memcpy` calls.
+#[must_use]
+#[derive(Clone)]
+struct DiagnosticBuilderInner<'a> {
+    handler: &'a Handler,
     diagnostic: Diagnostic,
     allow_suggestions: bool,
 }
@@ -52,7 +61,7 @@
     ) => {
         $(#[$attrs])*
         pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
-            self.diagnostic.$n($($name),*);
+            self.0.diagnostic.$n($($name),*);
             self
         }
     };
@@ -69,7 +78,7 @@
     ) => {
         $(#[$attrs])*
         pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
-            self.diagnostic.$n($($name),*);
+            self.0.diagnostic.$n($($name),*);
             self
         }
     };
@@ -79,24 +88,28 @@
     type Target = Diagnostic;
 
     fn deref(&self) -> &Diagnostic {
-        &self.diagnostic
+        &self.0.diagnostic
     }
 }
 
 impl<'a> DerefMut for DiagnosticBuilder<'a> {
     fn deref_mut(&mut self) -> &mut Diagnostic {
-        &mut self.diagnostic
+        &mut self.0.diagnostic
     }
 }
 
 impl<'a> DiagnosticBuilder<'a> {
+    pub fn handler(&self) -> &'a Handler{
+        self.0.handler
+    }
+
     /// Emit the diagnostic.
     pub fn emit(&mut self) {
         if self.cancelled() {
             return;
         }
 
-        self.handler.emit_db(&self);
+        self.0.handler.emit_db(&self);
         self.cancel();
     }
 
@@ -115,8 +128,8 @@
     /// Buffers the diagnostic for later emission, unless handler
     /// has disabled such buffering.
     pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
-        if self.handler.flags.dont_buffer_diagnostics ||
-            self.handler.flags.treat_err_as_bug.is_some()
+        if self.0.handler.flags.dont_buffer_diagnostics ||
+            self.0.handler.flags.treat_err_as_bug.is_some()
         {
             self.emit();
             return;
@@ -126,7 +139,7 @@
         // implements `Drop`.
         let diagnostic;
         unsafe {
-            diagnostic = std::ptr::read(&self.diagnostic);
+            diagnostic = std::ptr::read(&self.0.diagnostic);
             std::mem::forget(self);
         };
         // Logging here is useful to help track down where in logs an error was
@@ -144,7 +157,7 @@
         span: Option<S>,
     ) -> &mut Self {
         let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new());
-        self.diagnostic.sub(level, message, span, None);
+        self.0.diagnostic.sub(level, message, span, None);
         self
     }
 
@@ -160,7 +173,7 @@
     /// locally in whichever way makes the most sense.
     pub fn delay_as_bug(&mut self) {
         self.level = Level::Bug;
-        self.handler.delay_as_bug(self.diagnostic.clone());
+        self.0.handler.delay_as_bug(self.0.diagnostic.clone());
         self.cancel();
     }
 
@@ -171,7 +184,7 @@
     /// then the snippet will just include that `Span`, which is
     /// called the primary span.
     pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
-        self.diagnostic.span_label(span, label);
+        self.0.diagnostic.span_label(span, label);
         self
     }
 
@@ -208,10 +221,10 @@
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.multipart_suggestion(
+        self.0.diagnostic.multipart_suggestion(
             msg,
             suggestion,
             applicability,
@@ -225,10 +238,10 @@
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.tool_only_multipart_suggestion(
+        self.0.diagnostic.tool_only_multipart_suggestion(
             msg,
             suggestion,
             applicability,
@@ -236,7 +249,6 @@
         self
     }
 
-
     pub fn span_suggestion(
         &mut self,
         sp: Span,
@@ -244,10 +256,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestion(
+        self.0.diagnostic.span_suggestion(
             sp,
             msg,
             suggestion,
@@ -263,10 +275,10 @@
         suggestions: impl Iterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestions(
+        self.0.diagnostic.span_suggestions(
             sp,
             msg,
             suggestions,
@@ -282,10 +294,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestion_short(
+        self.0.diagnostic.span_suggestion_short(
             sp,
             msg,
             suggestion,
@@ -301,10 +313,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.span_suggestion_hidden(
+        self.0.diagnostic.span_suggestion_hidden(
             sp,
             msg,
             suggestion,
@@ -320,10 +332,10 @@
         suggestion: String,
         applicability: Applicability,
     ) -> &mut Self {
-        if !self.allow_suggestions {
+        if !self.0.allow_suggestions {
             return self
         }
-        self.diagnostic.tool_only_span_suggestion(
+        self.0.diagnostic.tool_only_span_suggestion(
             sp,
             msg,
             suggestion,
@@ -336,7 +348,7 @@
     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
 
     pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
-        self.allow_suggestions = allow;
+        self.0.allow_suggestions = allow;
         self
     }
 
@@ -359,19 +371,18 @@
 
     /// Creates a new `DiagnosticBuilder` with an already constructed
     /// diagnostic.
-    pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
-                         -> DiagnosticBuilder<'a> {
-        DiagnosticBuilder {
+    pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
+        DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
             handler,
             diagnostic,
             allow_suggestions: true,
-        }
+        }))
     }
 }
 
 impl<'a> Debug for DiagnosticBuilder<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.diagnostic.fmt(f)
+        self.0.diagnostic.fmt(f)
     }
 }
 
@@ -381,7 +392,7 @@
     fn drop(&mut self) {
         if !panicking() && !self.cancelled() {
             let mut db = DiagnosticBuilder::new(
-                self.handler,
+                self.0.handler,
                 Level::Bug,
                 "the following error was constructed but not emitted",
             );
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 0ce69ee..6660836 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -385,7 +385,7 @@
                                           &mut primary_span,
                                           &mut children,
                                           &db.level,
-                                          db.handler.flags.external_macro_backtrace);
+                                          db.handler().flags.external_macro_backtrace);
 
         self.emit_messages_default(&db.level,
                                    &db.styled_message(),
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 6585633..c1fba41 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -845,3 +845,10 @@
         }
     }
 }
+
+#[macro_export]
+macro_rules! pluralise {
+    ($x:expr) => {
+        if $x != 1 { "s" } else { "" }
+    };
+}
diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml
index a931ad3..659c4c8 100644
--- a/src/librustc_incremental/Cargo.toml
+++ b/src/librustc_incremental/Cargo.toml
@@ -12,7 +12,7 @@
 [dependencies]
 graphviz = { path = "../libgraphviz" }
 log = "0.4"
-rand = "0.6"
+rand = "0.7"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs
index 046fdc7..e08eeaf 100644
--- a/src/librustc_incremental/assert_module_sources.rs
+++ b/src/librustc_incremental/assert_module_sources.rs
@@ -27,7 +27,7 @@
 use rustc::ty::TyCtxt;
 use std::collections::BTreeSet;
 use syntax::ast;
-use syntax::symbol::{Symbol, sym};
+use syntax::symbol::{InternedString, Symbol, sym};
 use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED,
                  ATTR_EXPECTED_CGU_REUSE};
 
@@ -45,8 +45,8 @@
             .collect_and_partition_mono_items(LOCAL_CRATE)
             .1
             .iter()
-            .map(|cgu| format!("{}", cgu.name()))
-            .collect::<BTreeSet<String>>();
+            .map(|cgu| *cgu.name())
+            .collect::<BTreeSet<InternedString>>();
 
         let ams = AssertModuleSource {
             tcx,
@@ -61,7 +61,7 @@
 
 struct AssertModuleSource<'tcx> {
     tcx: TyCtxt<'tcx>,
-    available_cgus: BTreeSet<String>,
+    available_cgus: BTreeSet<InternedString>,
 }
 
 impl AssertModuleSource<'tcx> {
@@ -127,7 +127,7 @@
 
         debug!("mapping '{}' to cgu name '{}'", self.field(attr, MODULE), cgu_name);
 
-        if !self.available_cgus.contains(&cgu_name.as_str()[..]) {
+        if !self.available_cgus.contains(&cgu_name) {
             self.tcx.sess.span_err(attr.span,
                 &format!("no module named `{}` (mangled: {}). \
                           Available modules: {}",
@@ -135,7 +135,7 @@
                     cgu_name,
                     self.available_cgus
                         .iter()
-                        .cloned()
+                        .map(|cgu| cgu.as_str().to_string())
                         .collect::<Vec<_>>()
                         .join(", ")));
         }
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 16b377d..f629310 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -34,3 +34,4 @@
 rustc_privacy = { path = "../librustc_privacy" }
 rustc_resolve = { path = "../librustc_resolve" }
 tempfile = "3.0.5"
+once_cell = "1"
diff --git a/src/librustc_interface/build.rs b/src/librustc_interface/build.rs
new file mode 100644
index 0000000..79a343e
--- /dev/null
+++ b/src/librustc_interface/build.rs
@@ -0,0 +1,4 @@
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-env-changed=RUSTC_INSTALL_BINDIR");
+}
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 3cfae16..e8e8da6 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -41,7 +41,6 @@
 use syntax::parse::{self, PResult};
 use syntax::util::node_count::NodeCounter;
 use syntax::symbol::Symbol;
-use syntax::feature_gate::AttributeType;
 use syntax_pos::FileName;
 use syntax_ext;
 
@@ -219,7 +218,6 @@
 
 pub struct PluginInfo {
     syntax_exts: Vec<NamedSyntaxExtension>,
-    attributes: Vec<(Symbol, AttributeType)>,
 }
 
 pub fn register_plugins<'a>(
@@ -312,12 +310,9 @@
     }
 
     *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
-    *sess.plugin_attributes.borrow_mut() = attributes.clone();
+    *sess.plugin_attributes.borrow_mut() = attributes;
 
-    Ok((krate, PluginInfo {
-        syntax_exts,
-        attributes,
-    }))
+    Ok((krate, PluginInfo { syntax_exts }))
 }
 
 fn configure_and_expand_inner<'a>(
@@ -329,7 +324,6 @@
     crate_loader: &'a mut CrateLoader<'a>,
     plugin_info: PluginInfo,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
-    let attributes = plugin_info.attributes;
     time(sess, "pre ast expansion lint checks", || {
         lint::check_ast_crate(
             sess,
@@ -522,7 +516,6 @@
             &krate,
             &sess.parse_sess,
             &sess.features_untracked(),
-            &attributes,
             sess.opts.unstable_features,
         );
     });
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 9eaf7b7..b81f814 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -289,20 +289,39 @@
     backend
 }
 
-pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
-    // For now we only allow this function to be called once as it'll dlopen a
-    // few things, which seems to work best if we only do that once. In
-    // general this assertion never trips due to the once guard in `get_codegen_backend`,
-    // but there's a few manual calls to this function in this file we protect
-    // against.
-    static LOADED: AtomicBool = AtomicBool::new(false);
-    assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
-            "cannot load the default codegen backend twice");
+// This is used for rustdoc, but it uses similar machinery to codegen backend
+// loading, so we leave the code here. It is potentially useful for other tools
+// that want to invoke the rustc binary while linking to rustc as well.
+pub fn rustc_path<'a>() -> Option<&'a Path> {
+    static RUSTC_PATH: once_cell::sync::OnceCell<Option<PathBuf>> =
+        once_cell::sync::OnceCell::new();
 
+    const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR");
+
+    RUSTC_PATH.get_or_init(|| get_rustc_path_inner(BIN_PATH)).as_ref().map(|v| &**v)
+}
+
+fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
+    sysroot_candidates().iter()
+        .filter_map(|sysroot| {
+            let candidate = sysroot.join(bin_path).join(if cfg!(target_os = "windows") {
+                "rustc.exe"
+            } else {
+                "rustc"
+            });
+            if candidate.exists() {
+                Some(candidate)
+            } else {
+                None
+            }
+        })
+        .next()
+}
+
+fn sysroot_candidates() -> Vec<PathBuf> {
     let target = session::config::host_triple();
     let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()];
-    let path = current_dll_path()
-        .and_then(|s| s.canonicalize().ok());
+    let path = current_dll_path().and_then(|s| s.canonicalize().ok());
     if let Some(dll) = path {
         // use `parent` twice to chop off the file name and then also the
         // directory containing the dll which should be either `lib` or `bin`.
@@ -327,69 +346,7 @@
         }
     }
 
-    let sysroot = sysroot_candidates.iter()
-        .map(|sysroot| {
-            let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
-            sysroot.join(libdir).with_file_name(
-                option_env!("CFG_CODEGEN_BACKENDS_DIR").unwrap_or("codegen-backends"))
-        })
-        .filter(|f| {
-            info!("codegen backend candidate: {}", f.display());
-            f.exists()
-        })
-        .next();
-    let sysroot = sysroot.unwrap_or_else(|| {
-        let candidates = sysroot_candidates.iter()
-            .map(|p| p.display().to_string())
-            .collect::<Vec<_>>()
-            .join("\n* ");
-        let err = format!("failed to find a `codegen-backends` folder \
-                           in the sysroot candidates:\n* {}", candidates);
-        early_error(ErrorOutputType::default(), &err);
-    });
-    info!("probing {} for a codegen backend", sysroot.display());
-
-    let d = sysroot.read_dir().unwrap_or_else(|e| {
-        let err = format!("failed to load default codegen backend, couldn't \
-                           read `{}`: {}", sysroot.display(), e);
-        early_error(ErrorOutputType::default(), &err);
-    });
-
-    let mut file: Option<PathBuf> = None;
-
-    let expected_name = format!("rustc_codegen_llvm-{}", backend_name);
-    for entry in d.filter_map(|e| e.ok()) {
-        let path = entry.path();
-        let filename = match path.file_name().and_then(|s| s.to_str()) {
-            Some(s) => s,
-            None => continue,
-        };
-        if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
-            continue
-        }
-        let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
-        if name != expected_name {
-            continue
-        }
-        if let Some(ref prev) = file {
-            let err = format!("duplicate codegen backends found\n\
-                               first:  {}\n\
-                               second: {}\n\
-            ", prev.display(), path.display());
-            early_error(ErrorOutputType::default(), &err);
-        }
-        file = Some(path.clone());
-    }
-
-    match file {
-        Some(ref s) => return load_backend_from_dylib(s),
-        None => {
-            let err = format!("failed to load default codegen backend for `{}`, \
-                               no appropriate codegen dylib found in `{}`",
-                              backend_name, sysroot.display());
-            early_error(ErrorOutputType::default(), &err);
-        }
-    }
+    return sysroot_candidates;
 
     #[cfg(unix)]
     fn current_dll_path() -> Option<PathBuf> {
@@ -459,6 +416,85 @@
     }
 }
 
+pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
+    // For now we only allow this function to be called once as it'll dlopen a
+    // few things, which seems to work best if we only do that once. In
+    // general this assertion never trips due to the once guard in `get_codegen_backend`,
+    // but there's a few manual calls to this function in this file we protect
+    // against.
+    static LOADED: AtomicBool = AtomicBool::new(false);
+    assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
+            "cannot load the default codegen backend twice");
+
+    let target = session::config::host_triple();
+    let sysroot_candidates = sysroot_candidates();
+
+    let sysroot = sysroot_candidates.iter()
+        .map(|sysroot| {
+            let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
+            sysroot.join(libdir).with_file_name(
+                option_env!("CFG_CODEGEN_BACKENDS_DIR").unwrap_or("codegen-backends"))
+        })
+        .filter(|f| {
+            info!("codegen backend candidate: {}", f.display());
+            f.exists()
+        })
+        .next();
+    let sysroot = sysroot.unwrap_or_else(|| {
+        let candidates = sysroot_candidates.iter()
+            .map(|p| p.display().to_string())
+            .collect::<Vec<_>>()
+            .join("\n* ");
+        let err = format!("failed to find a `codegen-backends` folder \
+                           in the sysroot candidates:\n* {}", candidates);
+        early_error(ErrorOutputType::default(), &err);
+    });
+    info!("probing {} for a codegen backend", sysroot.display());
+
+    let d = sysroot.read_dir().unwrap_or_else(|e| {
+        let err = format!("failed to load default codegen backend, couldn't \
+                           read `{}`: {}", sysroot.display(), e);
+        early_error(ErrorOutputType::default(), &err);
+    });
+
+    let mut file: Option<PathBuf> = None;
+
+    let expected_name = format!("rustc_codegen_llvm-{}", backend_name);
+    for entry in d.filter_map(|e| e.ok()) {
+        let path = entry.path();
+        let filename = match path.file_name().and_then(|s| s.to_str()) {
+            Some(s) => s,
+            None => continue,
+        };
+        if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
+            continue
+        }
+        let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
+        if name != expected_name {
+            continue
+        }
+        if let Some(ref prev) = file {
+            let err = format!("duplicate codegen backends found\n\
+                               first:  {}\n\
+                               second: {}\n\
+            ", prev.display(), path.display());
+            early_error(ErrorOutputType::default(), &err);
+        }
+        file = Some(path.clone());
+    }
+
+    match file {
+        Some(ref s) => return load_backend_from_dylib(s),
+        None => {
+            let err = format!("failed to load default codegen backend for `{}`, \
+                               no appropriate codegen dylib found in `{}`",
+                              backend_name, sysroot.display());
+            early_error(ErrorOutputType::default(), &err);
+        }
+    }
+
+}
+
 pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
     use std::hash::Hasher;
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index aecf5c5..cf19a9e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -669,6 +669,22 @@
     }
 }
 
+fn lint_deprecated_attr(
+    cx: &EarlyContext<'_>,
+    attr: &ast::Attribute,
+    msg: &str,
+    suggestion: Option<&str>,
+) {
+    cx.struct_span_lint(DEPRECATED, attr.span, &msg)
+        .span_suggestion_short(
+            attr.span,
+            suggestion.unwrap_or("remove this attribute"),
+            String::new(),
+            Applicability::MachineApplicable
+        )
+        .emit();
+}
+
 impl EarlyLintPass for DeprecatedAttr {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         for &&(n, _, _, ref g) in &self.depr_attrs {
@@ -679,18 +695,15 @@
                                              _) = g {
                     let msg = format!("use of deprecated attribute `{}`: {}. See {}",
                                       name, reason, link);
-                    let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg);
-                    err.span_suggestion_short(
-                        attr.span,
-                        suggestion.unwrap_or("remove this attribute"),
-                        String::new(),
-                        Applicability::MachineApplicable
-                    );
-                    err.emit();
+                    lint_deprecated_attr(cx, attr, &msg, suggestion);
                 }
                 return;
             }
         }
+        if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) {
+            let msg = format!("use of deprecated attribute `{}`: no longer used.", attr.path);
+            lint_deprecated_attr(cx, attr, &msg, None);
+        }
     }
 }
 
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 217e10a..3b8c06b 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -624,7 +624,7 @@
                     AdtKind::Struct => {
                         if !def.repr.c() && !def.repr.transparent() {
                             return FfiUnsafe {
-                                ty: ty,
+                                ty,
                                 reason: "this struct has unspecified layout",
                                 help: Some("consider adding a `#[repr(C)]` or \
                                             `#[repr(transparent)]` attribute to this struct"),
@@ -633,7 +633,7 @@
 
                         if def.non_enum_variant().fields.is_empty() {
                             return FfiUnsafe {
-                                ty: ty,
+                                ty,
                                 reason: "this struct has no fields",
                                 help: Some("consider adding a member to this struct"),
                             };
@@ -669,7 +669,7 @@
                     AdtKind::Union => {
                         if !def.repr.c() && !def.repr.transparent() {
                             return FfiUnsafe {
-                                ty: ty,
+                                ty,
                                 reason: "this union has unspecified layout",
                                 help: Some("consider adding a `#[repr(C)]` or \
                                             `#[repr(transparent)]` attribute to this union"),
@@ -678,7 +678,7 @@
 
                         if def.non_enum_variant().fields.is_empty() {
                             return FfiUnsafe {
-                                ty: ty,
+                                ty,
                                 reason: "this union has no fields",
                                 help: Some("consider adding a field to this union"),
                             };
@@ -721,7 +721,7 @@
                             // Special-case types like `Option<extern fn()>`.
                             if !is_repr_nullable_ptr(cx, ty, def, substs) {
                                 return FfiUnsafe {
-                                    ty: ty,
+                                    ty,
                                     reason: "enum has no representation hint",
                                     help: Some("consider adding a `#[repr(C)]`, \
                                                 `#[repr(transparent)]`, or integer `#[repr(...)]` \
@@ -750,7 +750,7 @@
                                     }
                                     FfiPhantom(..) => {
                                         return FfiUnsafe {
-                                            ty: ty,
+                                            ty,
                                             reason: "this enum contains a PhantomData field",
                                             help: None,
                                         };
@@ -764,13 +764,13 @@
             }
 
             ty::Char => FfiUnsafe {
-                ty: ty,
+                ty,
                 reason: "the `char` type has no C equivalent",
                 help: Some("consider using `u32` or `libc::wchar_t` instead"),
             },
 
             ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe {
-                ty: ty,
+                ty,
                 reason: "128-bit integers don't currently have a known stable ABI",
                 help: None,
             },
@@ -779,25 +779,25 @@
             ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
 
             ty::Slice(_) => FfiUnsafe {
-                ty: ty,
+                ty,
                 reason: "slices have no C equivalent",
                 help: Some("consider using a raw pointer instead"),
             },
 
             ty::Dynamic(..) => FfiUnsafe {
-                ty: ty,
+                ty,
                 reason: "trait objects have no C equivalent",
                 help: None,
             },
 
             ty::Str => FfiUnsafe {
-                ty: ty,
+                ty,
                 reason: "string slices have no C equivalent",
                 help: Some("consider using `*const u8` and a length instead"),
             },
 
             ty::Tuple(..) => FfiUnsafe {
-                ty: ty,
+                ty,
                 reason: "tuples have unspecified layout",
                 help: Some("consider using a struct instead"),
             },
@@ -811,7 +811,7 @@
                 match sig.abi() {
                     Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
                         return FfiUnsafe {
-                            ty: ty,
+                            ty,
                             reason: "this function pointer has Rust-specific calling convention",
                             help: Some("consider using an `extern fn(...) -> ...` \
                                         function pointer instead"),
@@ -855,11 +855,76 @@
             ty::UnnormalizedProjection(..) |
             ty::Projection(..) |
             ty::Opaque(..) |
-            ty::FnDef(..) => bug!("Unexpected type in foreign function"),
+            ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
+        }
+    }
+
+    fn emit_ffi_unsafe_type_lint(
+        &mut self,
+        ty: Ty<'tcx>,
+        sp: Span,
+        note: &str,
+        help: Option<&str>,
+    ) {
+        let mut diag = self.cx.struct_span_lint(
+            IMPROPER_CTYPES,
+            sp,
+            &format!("`extern` block uses type `{}`, which is not FFI-safe", ty),
+        );
+        diag.span_label(sp, "not FFI-safe");
+        if let Some(help) = help {
+            diag.help(help);
+        }
+        diag.note(note);
+        if let ty::Adt(def, _) = ty.sty {
+            if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) {
+                diag.span_note(sp, "type defined here");
+            }
+        }
+        diag.emit();
+    }
+
+    fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
+        use crate::rustc::ty::TypeFoldable;
+
+        struct ProhibitOpaqueTypes<'tcx> {
+            ty: Option<Ty<'tcx>>,
+        };
+
+        impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+                if let ty::Opaque(..) = ty.sty {
+                    self.ty = Some(ty);
+                    true
+                } else {
+                    ty.super_visit_with(self)
+                }
+            }
+        }
+
+        let mut visitor = ProhibitOpaqueTypes { ty: None };
+        ty.visit_with(&mut visitor);
+        if let Some(ty) = visitor.ty {
+            self.emit_ffi_unsafe_type_lint(
+                ty,
+                sp,
+                "opaque types have no C equivalent",
+                None,
+            );
+            true
+        } else {
+            false
         }
     }
 
     fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
+        // We have to check for opaque types before `normalize_erasing_regions`,
+        // which will replace opaque types with their underlying concrete type.
+        if self.check_for_opaque_ty(sp, ty) {
+            // We've already emitted an error due to an opaque type.
+            return;
+        }
+
         // it is only OK to use this function because extern fns cannot have
         // any generic types right now:
         let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
@@ -867,24 +932,10 @@
         match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
             FfiResult::FfiSafe => {}
             FfiResult::FfiPhantom(ty) => {
-                self.cx.span_lint(IMPROPER_CTYPES,
-                                  sp,
-                                  &format!("`extern` block uses type `{}` which is not FFI-safe: \
-                                            composed only of PhantomData", ty));
+                self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None);
             }
-            FfiResult::FfiUnsafe { ty: unsafe_ty, reason, help } => {
-                let msg = format!("`extern` block uses type `{}` which is not FFI-safe: {}",
-                                  unsafe_ty, reason);
-                let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
-                if let Some(s) = help {
-                    diag.help(s);
-                }
-                if let ty::Adt(def, _) = unsafe_ty.sty {
-                    if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) {
-                        diag.span_note(sp, "type defined here");
-                    }
-                }
-                diag.emit();
+            FfiResult::FfiUnsafe { ty, reason, help } => {
+                self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
             }
         }
     }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 561bf20..c397509 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -370,7 +370,8 @@
                                      right_pos: Option<BytePos>) {
         match value.node {
             ast::ExprKind::Paren(ref inner) => {
-                if !Self::is_expr_parens_necessary(inner, followed_by_block) {
+                if !Self::is_expr_parens_necessary(inner, followed_by_block) &&
+                    value.attrs.is_empty() {
                     let expr_text = if let Ok(snippet) = cx.sess().source_map()
                         .span_to_snippet(value.span) {
                             snippet
@@ -618,24 +619,19 @@
             }
 
             // Trigger the lint if the nested item is a non-self single item
-            let node_ident;
-            match items[0].0.kind {
+            let node_name = match items[0].0.kind {
                 ast::UseTreeKind::Simple(rename, ..) => {
                     let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
                     if orig_ident.name == kw::SelfLower {
                         return;
                     }
-                    node_ident = rename.unwrap_or(orig_ident);
+                    rename.unwrap_or(orig_ident).name
                 }
-                ast::UseTreeKind::Glob => {
-                    node_ident = ast::Ident::from_str("*");
-                }
-                ast::UseTreeKind::Nested(_) => {
-                    return;
-                }
-            }
+                ast::UseTreeKind::Glob => Symbol::intern("*"),
+                ast::UseTreeKind::Nested(_) => return,
+            };
 
-            let msg = format!("braces around {} is unnecessary", node_ident.name);
+            let msg = format!("braces around {} is unnecessary", node_name);
             cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
         }
     }
diff --git a/src/librustc_lsan/build.rs b/src/librustc_lsan/build.rs
index d5f3e37..73720d8 100644
--- a/src/librustc_lsan/build.rs
+++ b/src/librustc_lsan/build.rs
@@ -4,6 +4,7 @@
 use cmake::Config;
 
 fn main() {
+    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
     if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
         return;
     }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index d6450f0..a1e3bbc 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -444,7 +444,8 @@
             .insert(local_span, (name.to_string(), data.get_span(id.index, sess)));
 
         LoadedMacro::MacroDef(ast::Item {
-            ident: ast::Ident::from_str(&name.as_str()),
+            // FIXME: cross-crate hygiene
+            ident: ast::Ident::with_dummy_span(name.as_symbol()),
             id: ast::DUMMY_NODE_ID,
             span: local_span,
             attrs: attrs.iter().cloned().collect(),
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index 66971bb..ada1a8c 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -8,7 +8,7 @@
 use syntax::attr;
 use syntax::source_map::Span;
 use syntax::feature_gate::{self, GateIssue};
-use syntax::symbol::{Symbol, sym};
+use syntax::symbol::{kw, sym, Symbol};
 use syntax::{span_err, struct_span_err};
 
 pub fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
@@ -132,7 +132,7 @@
 
 impl Collector<'tcx> {
     fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
-        if lib.name.as_ref().map(|s| s.as_str().is_empty()).unwrap_or(false) {
+        if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) {
             match span {
                 Some(span) => {
                     struct_span_err!(self.tcx.sess, span, E0454,
@@ -159,7 +159,7 @@
                                            sym::link_cfg,
                                            span.unwrap(),
                                            GateIssue::Language,
-                                           "is feature gated");
+                                           "is unstable");
         }
         if lib.kind == cstore::NativeStaticNobundle &&
            !self.tcx.features().static_nobundle {
@@ -167,7 +167,7 @@
                                            sym::static_nobundle,
                                            span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
                                            GateIssue::Language,
-                                           "kind=\"static-nobundle\" is feature gated");
+                                           "kind=\"static-nobundle\" is unstable");
         }
         self.libs.push(lib);
     }
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index e027360..0691390 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -24,6 +24,6 @@
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-byteorder = { version = "1.1", features = ["i128"] }
+byteorder = { version = "1.3" }
 rustc_apfloat = { path = "../librustc_apfloat" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index c9e6e7f..db19cbc 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -317,7 +317,7 @@
         // so extract `temp`.
         let temp = if let &mir::Place {
             base: mir::PlaceBase::Local(temp),
-            projection: None,
+            projection: box [],
         } = assigned_place {
             temp
         } else {
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index bfc7050..81359c6 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -2,8 +2,8 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
-    LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef,
-    ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+    LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue,
+    Statement, StatementKind, TerminatorKind, VarBindingForm,
 };
 use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashSet;
@@ -244,7 +244,7 @@
                 }
                 let span = if let Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } = place {
                     let decl = &self.body.local_decls[*local];
                     Some(decl.source_info.span)
@@ -614,17 +614,18 @@
                     projection,
                 } = first_borrowed_place;
 
-                let mut current = projection;
+                let mut cursor = &**projection;
+                while let [proj_base @ .., elem] = cursor {
+                    cursor = proj_base;
 
-                while let Some(box Projection { base: base_proj, elem }) = current {
                     match elem {
-                        ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => {
+                        ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
                             return Some((PlaceRef {
                                 base: base,
-                                projection: base_proj,
+                                projection: proj_base,
                             }, field));
                         },
-                        _ => current = base_proj,
+                        _ => {},
                     }
                 }
                 None
@@ -637,9 +638,10 @@
                     projection,
                 } = second_borrowed_place;
 
-                let mut current = projection;
+                let mut cursor = &**projection;
+                while let [proj_base @ .., elem] = cursor {
+                    cursor = proj_base;
 
-                while let Some(box Projection { base: proj_base, elem }) = current {
                     if let ProjectionElem::Field(field, _) = elem {
                         if let Some(union_ty) = union_ty(base, proj_base) {
                             if field != target_field
@@ -660,8 +662,6 @@
                             }
                         }
                     }
-
-                    current = proj_base;
                 }
                 None
             })
@@ -707,7 +707,7 @@
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.var_or_use();
 
-        assert!(root_place.projection.is_none());
+        assert!(root_place.projection.is_empty());
         let proper_span = match root_place.base {
             PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
             _ => drop_span,
@@ -716,7 +716,7 @@
         if self.access_place_error_reported
             .contains(&(Place {
                 base: root_place.base.clone(),
-                projection: root_place.projection.clone(),
+                projection: root_place.projection.to_vec().into_boxed_slice(),
             }, borrow_span))
         {
             debug!(
@@ -729,7 +729,7 @@
         self.access_place_error_reported
             .insert((Place {
                 base: root_place.base.clone(),
-                projection: root_place.projection.clone(),
+                projection: root_place.projection.to_vec().into_boxed_slice(),
             }, borrow_span));
 
         if let StorageDeadOrDrop::Destructor(dropped_ty) =
@@ -1107,7 +1107,7 @@
             let local_kind = match borrow.borrowed_place {
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } => {
                     match self.body.local_kind(local) {
                         LocalKind::ReturnPointer
@@ -1136,7 +1136,7 @@
                 .unwrap();
             let local = if let PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } = root_place {
                 local
             } else {
@@ -1446,7 +1446,7 @@
     ) {
         let (from_arg, local_decl) = if let Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         } = *err_place {
             if let LocalKind::Arg = self.body.local_kind(local) {
                 (true, Some(&self.body.local_decls[local]))
@@ -1519,20 +1519,21 @@
     fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
         let tcx = self.infcx.tcx;
         match place.projection {
-            None => {
+            [] => {
                 StorageDeadOrDrop::LocalStorageDead
             }
-            Some(box Projection { ref base, ref elem }) => {
+            [proj_base @ .., elem] => {
+                // FIXME(spastorino) make this iterate
                 let base_access = self.classify_drop_access_kind(PlaceRef {
                     base: place.base,
-                    projection: base,
+                    projection: proj_base,
                 });
                 match elem {
                     ProjectionElem::Deref => match base_access {
                         StorageDeadOrDrop::LocalStorageDead
                         | StorageDeadOrDrop::BoxedStorageDead => {
                             assert!(
-                                Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(),
+                                Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(),
                                 "Drop of value behind a reference or raw pointer"
                             );
                             StorageDeadOrDrop::BoxedStorageDead
@@ -1540,7 +1541,7 @@
                         StorageDeadOrDrop::Destructor(_) => base_access,
                     },
                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
+                        let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
                         match base_ty.sty {
                             ty::Adt(def, _) if def.has_dtor(tcx) => {
                                 // Report the outermost adt with a destructor
@@ -1598,7 +1599,7 @@
             "annotate_argument_and_return_for_borrow: location={:?}",
             location
         );
-        if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
+        if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
              = &self.body[location.block].statements.get(location.statement_index)
         {
             debug!(
@@ -1609,7 +1610,7 @@
             let mut target = *match reservation {
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } if self.body.local_kind(*local) == LocalKind::Temp => local,
                 _ => return None,
             };
@@ -1623,11 +1624,13 @@
                     target, stmt
                 );
                 if let StatementKind::Assign(
-                    Place {
-                        base: PlaceBase::Local(assigned_to),
-                        projection: None,
-                    },
-                    box rvalue
+                    box(
+                        Place {
+                            base: PlaceBase::Local(assigned_to),
+                            projection: box [],
+                        },
+                        rvalue
+                    )
                 ) = &stmt.kind {
                     debug!(
                         "annotate_argument_and_return_for_borrow: assigned_to={:?} \
@@ -1753,7 +1756,7 @@
             if let TerminatorKind::Call {
                 destination: Some((Place {
                     base: PlaceBase::Local(assigned_to),
-                    projection: None,
+                    projection: box [],
                 }, _)),
                 args,
                 ..
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 9f25e98..5bccd28 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -41,7 +41,7 @@
         let mut target = place.local_or_deref_local();
         for stmt in &self.body[location.block].statements[location.statement_index..] {
             debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
-            if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind {
+            if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
                 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
                 match from {
                     Operand::Copy(ref place) |
@@ -152,7 +152,7 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 self.append_local_to_string(*local, buf)?;
             }
@@ -162,7 +162,7 @@
                         kind: StaticKind::Promoted(..),
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => {
                 buf.push_str("promoted");
             }
@@ -173,15 +173,15 @@
                         def_id,
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => {
                 buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
             }
             PlaceRef {
                 base,
-                projection: Some(ref proj),
+                projection: [proj_base @ .., elem],
             } => {
-                match proj.elem {
+                match elem {
                     ProjectionElem::Deref => {
                         let upvar_field_projection =
                             self.is_upvar_field_projection(place);
@@ -199,20 +199,20 @@
                                 self.append_place_to_string(
                                     PlaceRef {
                                         base,
-                                        projection: &proj.base,
+                                        projection: proj_base,
                                     },
                                     buf,
                                     autoderef,
                                     &including_downcast,
                                 )?;
                             } else {
-                                match (&proj.base, base) {
-                                    (None, PlaceBase::Local(local)) => {
+                                match (proj_base, base) {
+                                    ([], PlaceBase::Local(local)) => {
                                         if self.body.local_decls[*local].is_ref_for_guard() {
                                             self.append_place_to_string(
                                                 PlaceRef {
                                                     base,
-                                                    projection: &proj.base,
+                                                    projection: proj_base,
                                                 },
                                                 buf,
                                                 autoderef,
@@ -224,7 +224,7 @@
                                             self.append_place_to_string(
                                                 PlaceRef {
                                                     base,
-                                                    projection: &proj.base,
+                                                    projection: proj_base,
                                                 },
                                                 buf,
                                                 autoderef,
@@ -238,7 +238,7 @@
                                         self.append_place_to_string(
                                             PlaceRef {
                                                 base,
-                                                projection: &proj.base,
+                                                projection: proj_base,
                                             },
                                             buf,
                                             autoderef,
@@ -253,7 +253,7 @@
                         self.append_place_to_string(
                             PlaceRef {
                                 base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             buf,
                             autoderef,
@@ -275,12 +275,12 @@
                         } else {
                             let field_name = self.describe_field(PlaceRef {
                                 base,
-                                projection: &proj.base,
-                            }, field);
+                                projection: proj_base,
+                            }, *field);
                             self.append_place_to_string(
                                 PlaceRef {
                                     base,
-                                    projection: &proj.base,
+                                    projection: proj_base,
                                 },
                                 buf,
                                 autoderef,
@@ -295,14 +295,14 @@
                         self.append_place_to_string(
                             PlaceRef {
                                 base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             buf,
                             autoderef,
                             &including_downcast,
                         )?;
                         buf.push_str("[");
-                        if self.append_local_to_string(index, buf).is_err() {
+                        if self.append_local_to_string(*index, buf).is_err() {
                             buf.push_str("_");
                         }
                         buf.push_str("]");
@@ -315,7 +315,7 @@
                         self.append_place_to_string(
                             PlaceRef {
                                 base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             },
                             buf,
                             autoderef,
@@ -349,28 +349,30 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 let local = &self.body.local_decls[*local];
                 self.describe_field_from_ty(&local.ty, field, None)
             }
             PlaceRef {
                 base: PlaceBase::Static(static_),
-                projection: None,
+                projection: [],
             } =>
                 self.describe_field_from_ty(&static_.ty, field, None),
             PlaceRef {
                 base,
-                projection: Some(proj),
-            } => match proj.elem {
-                ProjectionElem::Deref => self.describe_field(PlaceRef {
-                    base,
-                    projection: &proj.base,
-                }, field),
+                projection: [proj_base @ .., elem],
+            } => match elem {
+                ProjectionElem::Deref => {
+                    self.describe_field(PlaceRef {
+                        base,
+                        projection: proj_base,
+                    }, field)
+                }
                 ProjectionElem::Downcast(_, variant_index) => {
                     let base_ty =
                         Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty;
-                    self.describe_field_from_ty(&base_ty, field, Some(variant_index))
+                    self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
                 }
                 ProjectionElem::Field(_, field_type) => {
                     self.describe_field_from_ty(&field_type, field, None)
@@ -380,7 +382,7 @@
                 | ProjectionElem::Subslice { .. } => {
                     self.describe_field(PlaceRef {
                         base,
-                        projection: &proj.base,
+                        projection: proj_base,
                     }, field)
                 }
             },
@@ -445,7 +447,7 @@
                 def_id,
                 ..
             }),
-            projection: None,
+            projection: [],
         } = place_ref {
             let attrs = self.infcx.tcx.get_attrs(*def_id);
             let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
@@ -790,8 +792,7 @@
 
         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
         if let  StatementKind::Assign(
-            _,
-            box Rvalue::Aggregate(ref kind, ref places)
+            box(_, Rvalue::Aggregate(ref kind, ref places))
         ) = stmt.kind {
             let (def_id, is_generator) = match kind {
                 box AggregateKind::Closure(def_id, _) => (def_id, false),
@@ -828,10 +829,10 @@
             .get(location.statement_index)
         {
             Some(&Statement {
-                kind: StatementKind::Assign(Place {
+                kind: StatementKind::Assign(box(Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
-                }, _),
+                    projection: box [],
+                }, _)),
                 ..
             }) => local,
             _ => return OtherUse(use_span),
@@ -844,7 +845,7 @@
 
         for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
             if let StatementKind::Assign(
-                _, box Rvalue::Aggregate(ref kind, ref places)
+                box(_, Rvalue::Aggregate(ref kind, ref places))
             ) = stmt.kind {
                 let (def_id, is_generator) = match kind {
                     box AggregateKind::Closure(def_id, _) => (def_id, false),
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 9ad7cbc..1d35762 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -10,10 +10,10 @@
 use rustc::middle::borrowck::SignalledError;
 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc::mir::{
-    ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef,
-    Static, StaticKind
+    ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem,
+    PlaceRef, Static, StaticKind
 };
-use rustc::mir::{Field, Projection, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
+use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc::mir::{Terminator, TerminatorKind};
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt};
@@ -546,7 +546,7 @@
         self.check_activations(location, span, flow_state);
 
         match stmt.kind {
-            StatementKind::Assign(ref lhs, ref rhs) => {
+            StatementKind::Assign(box(ref lhs, ref rhs)) => {
                 self.consume_rvalue(
                     location,
                     (rhs, span),
@@ -561,7 +561,7 @@
                     flow_state,
                 );
             }
-            StatementKind::FakeRead(_, ref place) => {
+            StatementKind::FakeRead(_, box ref place) => {
                 // Read for match doesn't access any memory and is used to
                 // assert that a place is safe and live. So we don't have to
                 // do any checks here.
@@ -905,7 +905,7 @@
 
 struct RootPlace<'d, 'tcx> {
     place_base: &'d PlaceBase<'tcx>,
-    place_projection: &'d Option<Box<Projection<'tcx>>>,
+    place_projection: &'d [PlaceElem<'tcx>],
     is_local_mutation_allowed: LocalMutationIsAllowed,
 }
 
@@ -1191,7 +1191,7 @@
         // before (at this point in the flow).
         if let Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         } = place_span.0 {
             if let Mutability::Not = self.body.local_decls[*local].mutability {
                 // check for reassignments to immutable local variables
@@ -1331,7 +1331,7 @@
 
     fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
         let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
-            if place.projection.is_some() {
+            if !place.projection.is_empty() {
                 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
                     this.used_mut_upvars.push(field);
                 }
@@ -1346,11 +1346,11 @@
         match *operand {
             Operand::Move(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) |
             Operand::Copy(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) if self.body.local_decls[local].is_user_variable.is_none() => {
                 if self.body.local_decls[local].ty.is_mutable_ptr() {
                     // The variable will be marked as mutable by the borrow.
@@ -1387,7 +1387,7 @@
                 let stmt = &bbd.statements[loc.statement_index];
                 debug!("temporary assigned in: stmt={:?}", stmt);
 
-                if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind {
+                if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
                     propagate_closure_used_mut_place(self, source);
                 } else {
                     bug!("closures should only capture user variables \
@@ -1468,7 +1468,7 @@
         //
         // FIXME: allow thread-locals to borrow other thread locals?
 
-        assert!(root_place.projection.is_none());
+        assert!(root_place.projection.is_empty());
         let (might_be_alive, will_be_dropped) = match root_place.base {
             PlaceBase::Static(box Static {
                 kind: StaticKind::Promoted(..),
@@ -1756,13 +1756,13 @@
         flow_state: &Flows<'cx, 'tcx>,
     ) {
         debug!("check_if_assigned_path_is_moved place: {:?}", place);
-        // recur down place; dispatch to external checks when necessary
-        let mut place_projection = &place.projection;
 
         // None case => assigning to `x` does not require `x` be initialized.
-        while let Some(proj) = place_projection {
-            let Projection { ref base, ref elem } = **proj;
-            match *elem {
+        let mut cursor = &*place.projection;
+        while let [proj_base @ .., elem] = cursor {
+            cursor = proj_base;
+
+            match elem {
                 ProjectionElem::Index(_/*operand*/) |
                 ProjectionElem::ConstantIndex { .. } |
                 // assigning to P[i] requires P to be valid.
@@ -1778,7 +1778,7 @@
                         location, InitializationRequiringAction::Use,
                         (PlaceRef {
                             base: &place.base,
-                            projection: base,
+                            projection: proj_base,
                         }, span), flow_state);
                     // (base initialized; no need to
                     // recur further)
@@ -1795,14 +1795,14 @@
                     // assigning to `P.f` requires `P` itself
                     // be already initialized
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
+                    let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
                     match base_ty.sty {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
                                 location, InitializationRequiringAction::Assignment,
                                 (PlaceRef {
                                     base: &place.base,
-                                    projection: base,
+                                    projection: proj_base,
                                 }, span), flow_state);
 
                             // (base initialized; no need to
@@ -1815,7 +1815,7 @@
                         ty::Adt(..) | ty::Tuple(..) => {
                             check_parent_of_field(self, location, PlaceRef {
                                 base: &place.base,
-                                projection: base,
+                                projection: proj_base,
                             }, span, flow_state);
 
                             if let PlaceBase::Local(local) = place.base {
@@ -1835,8 +1835,6 @@
                     }
                 }
             }
-
-            place_projection = base;
         }
 
         fn check_parent_of_field<'cx, 'tcx>(
@@ -2084,7 +2082,7 @@
         match root_place {
             RootPlace {
                 place_base: PlaceBase::Local(local),
-                place_projection: None,
+                place_projection: [],
                 is_local_mutation_allowed,
             } => {
                 // If the local may have been initialized, and it is now currently being
@@ -2103,7 +2101,7 @@
             } => {}
             RootPlace {
                 place_base,
-                place_projection: place_projection @ Some(_),
+                place_projection: place_projection @ [.., _],
                 is_local_mutation_allowed: _,
             } => {
                 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -2115,7 +2113,7 @@
             }
             RootPlace {
                 place_base: PlaceBase::Static(..),
-                place_projection: None,
+                place_projection: [],
                 is_local_mutation_allowed: _,
             } => {}
         }
@@ -2131,7 +2129,7 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 let local = &self.body.local_decls[*local];
                 match local.mutability {
@@ -2162,7 +2160,7 @@
                     kind: StaticKind::Promoted(..),
                     ..
                 }),
-                projection: None,
+                projection: [],
             } =>
                 Ok(RootPlace {
                     place_base: place.base,
@@ -2175,7 +2173,7 @@
                     def_id,
                     ..
                 }),
-                projection: None,
+                projection: [],
             } => {
                 if !self.infcx.tcx.is_mutable_static(*def_id) {
                     Err(place)
@@ -2189,12 +2187,12 @@
             }
             PlaceRef {
                 base: _,
-                projection: Some(proj),
+                projection: [proj_base @ .., elem],
             } => {
-                match proj.elem {
+                match elem {
                     ProjectionElem::Deref => {
                         let base_ty =
-                            Place::ty_from(place.base, &proj.base, self.body, self.infcx.tcx).ty;
+                            Place::ty_from(place.base, proj_base, self.body, self.infcx.tcx).ty;
 
                         // Check the kind of deref to decide
                         match base_ty.sty {
@@ -2216,7 +2214,7 @@
 
                                         self.is_mutable(PlaceRef {
                                             base: place.base,
-                                            projection: &proj.base,
+                                            projection: proj_base,
                                         }, mode)
                                     }
                                 }
@@ -2240,7 +2238,7 @@
                             _ if base_ty.is_box() => {
                                 self.is_mutable(PlaceRef {
                                     base: place.base,
-                                    projection: &proj.base,
+                                    projection: proj_base,
                                 }, is_local_mutation_allowed)
                             }
                             // Deref should only be for reference, pointers or boxes
@@ -2297,7 +2295,7 @@
                                     // ```
                                     let _ = self.is_mutable(PlaceRef {
                                         base: place.base,
-                                        projection: &proj.base,
+                                        projection: proj_base,
                                     }, is_local_mutation_allowed)?;
                                     Ok(RootPlace {
                                         place_base: place.base,
@@ -2309,7 +2307,7 @@
                         } else {
                             self.is_mutable(PlaceRef {
                                 base: place.base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             }, is_local_mutation_allowed)
                         }
                     }
@@ -2326,21 +2324,15 @@
         let mut place_projection = place_ref.projection;
         let mut by_ref = false;
 
-        if let Some(box Projection {
-            base,
-            elem: ProjectionElem::Deref,
-        }) = place_projection {
-            place_projection = &base;
+        if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
+            place_projection = proj_base;
             by_ref = true;
         }
 
         match place_projection {
-            Some(box Projection {
-                base,
-                elem: ProjectionElem::Field(field, _ty),
-            }) => {
+            [base @ .., ProjectionElem::Field(field, _ty)] => {
                 let tcx = self.infcx.tcx;
-                let base_ty = Place::ty_from(place_ref.base, &base, self.body, tcx).ty;
+                let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty;
 
                 if (base_ty.is_closure() || base_ty.is_generator()) &&
                     (!by_ref || self.upvars[field.index()].by_ref) {
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index 0d13db2..aa732b0 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -89,11 +89,13 @@
                 // If that ever stops being the case, then the ever initialized
                 // flow could be used.
                 if let Some(StatementKind::Assign(
-                    Place {
-                        base: PlaceBase::Local(local),
-                        projection: None,
-                    },
-                    box Rvalue::Use(Operand::Move(move_from)),
+                    box(
+                        Place {
+                            base: PlaceBase::Local(local),
+                            projection: box [],
+                        },
+                        Rvalue::Use(Operand::Move(move_from))
+                    )
                 )) = self.body.basic_blocks()[location.block]
                     .statements
                     .get(location.statement_index)
@@ -274,16 +276,12 @@
         place: &Place<'tcx>,
         span: Span
     ) -> DiagnosticBuilder<'a> {
-        let description = if place.projection.is_none() {
+        let description = if place.projection.is_empty() {
             format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
         } else {
-            let mut base_static = &place.projection;
-            while let Some(box Projection { base: Some(ref proj), .. }) = base_static {
-                base_static = &proj.base;
-            }
             let base_static = PlaceRef {
                 base: &place.base,
-                projection: base_static,
+                projection: &place.projection[..1],
             };
 
             format!(
@@ -309,17 +307,19 @@
         let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
             .find_map(|p| self.is_upvar_field_projection(p));
 
-        let deref_base = match deref_target_place.projection {
-            Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef {
-                base: &deref_target_place.base,
-                projection: base,
-            },
+        let deref_base = match &deref_target_place.projection {
+            box [proj_base @ .., ProjectionElem::Deref] => {
+                PlaceRef {
+                    base: &deref_target_place.base,
+                    projection: proj_base,
+                }
+            }
             _ => bug!("deref_target_place is not a deref projection"),
         };
 
         if let PlaceRef {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: [],
         } = deref_base {
             let decl = &self.body.local_decls[*local];
             if decl.is_ref_for_guard() {
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index 8f2ce80..14b76d9 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -2,7 +2,7 @@
 use rustc::hir::Node;
 use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
 use rustc::mir::{
-    Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind
+    Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind
 };
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::indexed_vec::Idx;
@@ -47,12 +47,12 @@
         match the_place_err {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => {
                 item_msg = format!("`{}`", access_place_desc.unwrap());
                 if let Place {
                     base: PlaceBase::Local(_),
-                    projection: None,
+                    projection: box [],
                 } = access_place {
                     reason = ", as it is not declared as mutable".to_string();
                 } else {
@@ -65,14 +65,10 @@
 
             PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base,
-                        elem: ProjectionElem::Field(upvar_index, _),
-                    }),
+                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty
+                    Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
                 item_msg = format!("`{}`", access_place_desc.unwrap());
@@ -86,14 +82,10 @@
 
             PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base,
-                        elem: ProjectionElem::Deref,
-                    }),
+                projection: [proj_base @ .., ProjectionElem::Deref],
             } => {
                 if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
-                    base.is_none() &&
+                    proj_base.is_empty() &&
                     !self.upvars.is_empty() {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
                     debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
@@ -114,7 +106,7 @@
                             ", as `Fn` closures cannot mutate their captured variables".to_string()
                         }
                 } else if {
-                    if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) {
+                    if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) {
                         self.body.local_decls[*local].is_ref_for_guard()
                     } else {
                         false
@@ -125,7 +117,7 @@
                 } else {
                     let source = self.borrowed_content_source(PlaceRef {
                         base: the_place_err.base,
-                        projection: base,
+                        projection: proj_base,
                     });
                     let pointer_type = source.describe_for_immutable_place();
                     opt_source = Some(source);
@@ -151,7 +143,7 @@
                         kind: StaticKind::Promoted(..),
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => unreachable!(),
 
             PlaceRef {
@@ -161,11 +153,11 @@
                         def_id,
                         ..
                     }),
-                projection: None,
+                projection: [],
             } => {
                 if let Place {
                     base: PlaceBase::Static(_),
-                    projection: None,
+                    projection: box [],
                 } = access_place {
                     item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
                     reason = String::new();
@@ -178,33 +170,19 @@
 
             PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base: _,
-                        elem: ProjectionElem::Index(_),
-                    }),
+                projection: [.., ProjectionElem::Index(_)],
             }
             | PlaceRef {
                 base: _,
-                projection:
-                    Some(box Projection {
-                        base: _,
-                        elem: ProjectionElem::ConstantIndex { .. },
-                    }),
+                projection: [.., ProjectionElem::ConstantIndex { .. }],
             }
             | PlaceRef {
                 base: _,
-                projection: Some(box Projection {
-                    base: _,
-                    elem: ProjectionElem::Subslice { .. },
-                }),
+                projection: [.., ProjectionElem::Subslice { .. }],
             }
             | PlaceRef {
                 base: _,
-                projection: Some(box Projection {
-                    base: _,
-                    elem: ProjectionElem::Downcast(..),
-                }),
+                projection: [.., ProjectionElem::Downcast(..)],
             } => bug!("Unexpected immutable place."),
         }
 
@@ -262,22 +240,17 @@
             // after the field access).
             PlaceRef {
                 base,
-                projection: Some(box Projection {
-                    base: Some(box Projection {
-                        base: Some(box Projection {
-                            base: base_proj,
-                            elem: ProjectionElem::Deref,
-                        }),
-                        elem: ProjectionElem::Field(field, _),
-                    }),
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [proj_base @ ..,
+                             ProjectionElem::Deref,
+                             ProjectionElem::Field(field, _),
+                             ProjectionElem::Deref,
+                ],
             } => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
                 if let Some((span, message)) = annotate_struct_field(
                     self.infcx.tcx,
-                    Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty,
+                    Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty,
                     field,
                 ) {
                     err.span_suggestion(
@@ -292,7 +265,7 @@
             // Suggest removing a `&mut` from the use of a mutable reference.
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } if {
                 self.body.local_decls.get(*local).map(|local_decl| {
                     if let ClearCrossCrate::Set(
@@ -328,7 +301,7 @@
             // variable) mutations...
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } if self.body.local_decls[*local].can_be_made_mutable() => {
                 // ... but it doesn't make sense to suggest it on
                 // variables that are `ref x`, `ref mut x`, `&self`,
@@ -349,13 +322,10 @@
             // Also suggest adding mut for upvars
             PlaceRef {
                 base,
-                projection: Some(box Projection {
-                    base: proj_base,
-                    elem: ProjectionElem::Field(upvar_index, _),
-                }),
+                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(&base, &proj_base, self.body, self.infcx.tcx).ty
+                    Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -385,7 +355,7 @@
             // a local variable, then just suggest the user remove it.
             PlaceRef {
                 base: PlaceBase::Local(_),
-                projection: None,
+                projection: [],
             } if {
                     if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
                         snippet.starts_with("&mut ")
@@ -400,10 +370,7 @@
 
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             } if {
                 if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
                     self.body.local_decls[*local].is_user_variable
@@ -427,10 +394,7 @@
             // arbitrary base for the projection?
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             } if self.body.local_decls[*local].is_user_variable.is_some() =>
             {
                 let local_decl = &self.body.local_decls[*local];
@@ -510,10 +474,7 @@
 
             PlaceRef {
                 base,
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [ProjectionElem::Deref],
             // FIXME document what is this 1 magic number about
             } if *base == PlaceBase::Local(Local::new(1)) &&
                   !self.upvars.is_empty() =>
@@ -527,10 +488,7 @@
 
             PlaceRef {
                 base: _,
-                projection: Some(box Projection {
-                    base: _,
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: [.., ProjectionElem::Deref],
             } => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 5c23091..1e5f613 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -8,9 +8,8 @@
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection,
-    ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
-    UserTypeProjection,
+    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
+    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
@@ -229,14 +228,11 @@
             match place {
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } |
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: Some(box Projection {
-                        base: None,
-                        elem: ProjectionElem::Deref,
-                    }),
+                    projection: box [ProjectionElem::Deref],
                 } => {
                     debug!(
                         "Recording `killed` facts for borrows of local={:?} at location={:?}",
@@ -261,7 +257,7 @@
 
                 Place {
                     base: PlaceBase::Local(local),
-                    projection: Some(_),
+                    projection: box [.., _],
                 } => {
                     // Kill conflicting borrows of the innermost local.
                     debug!(
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index aba3ef1..eae2f83 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -274,7 +274,7 @@
                     if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
                         if let Place {
                             base: PlaceBase::Local(borrowed_local),
-                            projection: None,
+                            projection: box [],
                         } = place {
                              if body.local_decls[*borrowed_local].name.is_some()
                                 && local != *borrowed_local
@@ -495,11 +495,11 @@
                             Operand::Constant(c) => c.span,
                             Operand::Copy(Place {
                                 base: PlaceBase::Local(l),
-                                projection: None,
+                                projection: box [],
                             }) |
                             Operand::Move(Place {
                                 base: PlaceBase::Local(l),
-                                projection: None,
+                                projection: box [],
                             }) => {
                                 let local_decl = &self.body.local_decls[*l];
                                 if local_decl.name.is_none() {
@@ -541,10 +541,10 @@
         // it which simplifies the termination logic.
         let mut queue = vec![location];
         let mut target = if let Some(&Statement {
-            kind: StatementKind::Assign(Place {
+            kind: StatementKind::Assign(box(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
-            }, _),
+                projection: box [],
+            }, _)),
             ..
         }) = stmt
         {
@@ -567,7 +567,7 @@
                 debug!("was_captured_by_trait_object: stmt={:?}", stmt);
 
                 // The only kind of statement that we care about is assignments...
-                if let StatementKind::Assign(place, box rvalue) = &stmt.kind {
+                if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
                     let into = match place.local_or_deref_local() {
                         Some(into) => into,
                         None => {
@@ -583,11 +583,11 @@
                         Rvalue::Use(operand) => match operand {
                             Operand::Copy(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                             | Operand::Move(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                                 if *from == target =>
                             {
@@ -602,11 +602,11 @@
                         ) => match operand {
                             Operand::Copy(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                             | Operand::Move(Place {
                                 base: PlaceBase::Local(from),
-                                projection: None,
+                                projection: box [],
                             })
                                 if *from == target =>
                             {
@@ -639,7 +639,7 @@
                 if let TerminatorKind::Call {
                     destination: Some((Place {
                         base: PlaceBase::Local(dest),
-                        projection: None,
+                        projection: box [],
                     }, block)),
                     args,
                     ..
@@ -653,7 +653,7 @@
                     let found_target = args.iter().any(|arg| {
                         if let Operand::Move(Place {
                             base: PlaceBase::Local(potential),
-                            projection: None,
+                            projection: box [],
                         }) = arg {
                             *potential == target
                         } else {
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index 71106af..1d429e3 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -66,7 +66,7 @@
         self.check_activations(location);
 
         match statement.kind {
-            StatementKind::Assign(ref lhs, ref rhs) => {
+            StatementKind::Assign(box(ref lhs, ref rhs)) => {
                 self.consume_rvalue(
                     location,
                     rhs,
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index efa1858..26a89b4 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -13,7 +13,7 @@
 use rustc::mir::{ConstraintCategory, Location, Body};
 use rustc::ty::{self, RegionVid};
 use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_errors::{Diagnostic, DiagnosticBuilder};
+use rustc_errors::DiagnosticBuilder;
 use std::collections::VecDeque;
 use syntax::errors::Applicability;
 use syntax::symbol::kw;
@@ -22,7 +22,7 @@
 mod region_name;
 mod var_name;
 
-crate use self::region_name::{RegionName, RegionNameSource};
+crate use self::region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
 
 impl ConstraintDescription for ConstraintCategory {
     fn description(&self) -> &'static str {
@@ -54,6 +54,39 @@
     NotVisited,
 }
 
+/// Various pieces of state used when reporting borrow checker errors.
+pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
+    /// The region inference context used for borrow chekcing this MIR body.
+    #[allow(dead_code)] // FIXME(mark-i-m): used by outlives suggestions
+    region_infcx: &'b RegionInferenceContext<'tcx>,
+
+    /// The inference context used for type checking.
+    infcx: &'b InferCtxt<'a, 'tcx>,
+
+    /// The MIR def we are reporting errors on.
+    mir_def_id: DefId,
+
+    /// The MIR body we are reporting errors on (for convenience).
+    body: &'b Body<'tcx>,
+
+    /// Any upvars for the MIR body we have kept track of during borrow checking.
+    upvars: &'b [Upvar],
+}
+
+/// Information about the various region constraints involved in a borrow checker error.
+#[derive(Clone, Debug)]
+pub struct ErrorConstraintInfo {
+    // fr: outlived_fr
+    fr: RegionVid,
+    fr_is_local: bool,
+    outlived_fr: RegionVid,
+    outlived_fr_is_local: bool,
+
+    // Category and span for best blame constraint
+    category: ConstraintCategory,
+    span: Span,
+}
+
 impl<'tcx> RegionInferenceContext<'tcx> {
     /// Tries to find the best constraint to blame for the fact that
     /// `R: from_region`, where `R` is some region that meets
@@ -257,16 +290,16 @@
     /// ```
     ///
     /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
-    pub(super) fn report_error(
-        &self,
+    pub(super) fn report_error<'a>(
+        &'a self,
         body: &Body<'tcx>,
         upvars: &[Upvar],
-        infcx: &InferCtxt<'_, 'tcx>,
+        infcx: &'a InferCtxt<'a, 'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
         outlived_fr: RegionVid,
-        errors_buffer: &mut Vec<Diagnostic>,
-    ) {
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'a> {
         debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
 
         let (category, _, span) = self.best_blame_constraint(body, fr, |r| {
@@ -279,8 +312,7 @@
             let tables = infcx.tcx.typeck_tables_of(mir_def_id);
             let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
             if let Some(diag) = nice.try_report_from_nll() {
-                diag.buffer(errors_buffer);
-                return;
+                return diag;
             }
         }
 
@@ -293,45 +325,28 @@
             "report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
             fr_is_local, outlived_fr_is_local, category
         );
+
+        let errctx = ErrorReportingCtx {
+            region_infcx: self,
+            infcx,
+            mir_def_id,
+            body,
+            upvars,
+        };
+
+        let errci = ErrorConstraintInfo {
+            fr, outlived_fr, fr_is_local, outlived_fr_is_local, category, span
+        };
+
         match (category, fr_is_local, outlived_fr_is_local) {
             (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => {
-                self.report_fnmut_error(
-                    body,
-                    upvars,
-                    infcx,
-                    mir_def_id,
-                    fr,
-                    outlived_fr,
-                    span,
-                    errors_buffer,
-                )
+                self.report_fnmut_error(&errctx, &errci, renctx)
             }
             (ConstraintCategory::Assignment, true, false)
-            | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error(
-                body,
-                upvars,
-                infcx,
-                mir_def_id,
-                fr,
-                outlived_fr,
-                category,
-                span,
-                errors_buffer,
-            ),
-            _ => self.report_general_error(
-                body,
-                upvars,
-                infcx,
-                mir_def_id,
-                fr,
-                fr_is_local,
-                outlived_fr,
-                outlived_fr_is_local,
-                category,
-                span,
-                errors_buffer,
-            ),
-        };
+            | (ConstraintCategory::CallArgument, true, false) =>
+                self.report_escaping_data_error(&errctx, &errci, renctx),
+            _ => self.report_general_error(&errctx, &errci, renctx),
+        }
     }
 
     /// We have a constraint `fr1: fr2` that is not satisfied, where
@@ -379,19 +394,19 @@
     /// ```
     fn report_fnmut_error(
         &self,
-        body: &Body<'tcx>,
-        upvars: &[Upvar],
-        infcx: &InferCtxt<'_, 'tcx>,
-        mir_def_id: DefId,
-        _fr: RegionVid,
-        outlived_fr: RegionVid,
-        span: Span,
-        errors_buffer: &mut Vec<Diagnostic>,
-    ) {
-        let mut diag = infcx
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        errci: &ErrorConstraintInfo,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'_> {
+        let ErrorConstraintInfo {
+            outlived_fr, span, ..
+        } = errci;
+
+        let mut diag = errctx
+            .infcx
             .tcx
             .sess
-            .struct_span_err(span, "captured variable cannot escape `FnMut` closure body");
+            .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
 
         // We should check if the return type of this closure is in fact a closure - in that
         // case, we can special case the error further.
@@ -403,11 +418,9 @@
             "returns a reference to a captured variable which escapes the closure body"
         };
 
-        diag.span_label(span, message);
+        diag.span_label(*span, message);
 
-        match self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, &mut 1)
-            .unwrap().source
-        {
+        match self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap().source {
             RegionNameSource::NamedEarlyBoundRegion(fr_span)
             | RegionNameSource::NamedFreeRegion(fr_span)
             | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
@@ -427,7 +440,7 @@
         );
         diag.note("...therefore, they cannot allow references to captured variables to escape");
 
-        diag.buffer(errors_buffer);
+        diag
     }
 
     /// Reports a error specifically for when data is escaping a closure.
@@ -444,20 +457,22 @@
     /// ```
     fn report_escaping_data_error(
         &self,
-        body: &Body<'tcx>,
-        upvars: &[Upvar],
-        infcx: &InferCtxt<'_, 'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        outlived_fr: RegionVid,
-        category: ConstraintCategory,
-        span: Span,
-        errors_buffer: &mut Vec<Diagnostic>,
-    ) {
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        errci: &ErrorConstraintInfo,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'_> {
+        let ErrorReportingCtx {
+            infcx, body, upvars, ..
+        } = errctx;
+
+        let ErrorConstraintInfo {
+            span, category, ..
+        } = errci;
+
         let fr_name_and_span =
-            self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, fr);
+            self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.fr);
         let outlived_fr_name_and_span =
-            self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, outlived_fr);
+            self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.outlived_fr);
 
         let escapes_from = match self.universal_regions.defining_ty {
             DefiningTy::Closure(..) => "closure",
@@ -469,27 +484,23 @@
         // Revert to the normal error in these cases.
         // Assignments aren't "escapes" in function items.
         if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
-            || (category == ConstraintCategory::Assignment && escapes_from == "function")
+            || (*category == ConstraintCategory::Assignment && escapes_from == "function")
             || escapes_from == "const"
         {
             return self.report_general_error(
-                body,
-                upvars,
-                infcx,
-                mir_def_id,
-                fr,
-                true,
-                outlived_fr,
-                false,
-                category,
-                span,
-                errors_buffer,
+                errctx,
+                &ErrorConstraintInfo {
+                    fr_is_local: true,
+                    outlived_fr_is_local: false,
+                    .. *errci
+                },
+                renctx,
             );
         }
 
         let mut diag = borrowck_errors::borrowed_data_escapes_closure(
             infcx.tcx,
-            span,
+            *span,
             escapes_from,
         );
 
@@ -513,12 +524,12 @@
             );
 
             diag.span_label(
-                span,
+                *span,
                 format!("`{}` escapes the {} body here", fr_name, escapes_from),
             );
         }
 
-        diag.buffer(errors_buffer);
+        diag
     }
 
     /// Reports a region inference error for the general case with named/synthesized lifetimes to
@@ -538,41 +549,37 @@
     /// ```
     fn report_general_error(
         &self,
-        body: &Body<'tcx>,
-        upvars: &[Upvar],
-        infcx: &InferCtxt<'_, 'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        fr_is_local: bool,
-        outlived_fr: RegionVid,
-        outlived_fr_is_local: bool,
-        category: ConstraintCategory,
-        span: Span,
-        errors_buffer: &mut Vec<Diagnostic>,
-    ) {
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        errci: &ErrorConstraintInfo,
+        renctx: &mut RegionErrorNamingCtx,
+    ) -> DiagnosticBuilder<'_> {
+        let ErrorReportingCtx {
+            infcx, mir_def_id, ..
+        } = errctx;
+        let ErrorConstraintInfo {
+            fr, fr_is_local, outlived_fr, outlived_fr_is_local, span, category, ..
+        } = errci;
+
         let mut diag = infcx.tcx.sess.struct_span_err(
-            span,
+            *span,
             "lifetime may not live long enough"
         );
 
-        let counter = &mut 1;
-        let fr_name = self.give_region_a_name(
-            infcx, body, upvars, mir_def_id, fr, counter).unwrap();
-        fr_name.highlight_region_name(&mut diag);
-        let outlived_fr_name =
-            self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, counter).unwrap();
-        outlived_fr_name.highlight_region_name(&mut diag);
-
-        let mir_def_name = if infcx.tcx.is_closure(mir_def_id) {
+        let mir_def_name = if infcx.tcx.is_closure(*mir_def_id) {
             "closure"
         } else {
             "function"
         };
 
+        let fr_name = self.give_region_a_name(errctx, renctx, *fr).unwrap();
+        fr_name.highlight_region_name(&mut diag);
+        let outlived_fr_name = self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap();
+        outlived_fr_name.highlight_region_name(&mut diag);
+
         match (category, outlived_fr_is_local, fr_is_local) {
             (ConstraintCategory::Return, true, _) => {
                 diag.span_label(
-                    span,
+                    *span,
                     format!(
                         "{} was supposed to return data with lifetime `{}` but it is returning \
                          data with lifetime `{}`",
@@ -582,7 +589,7 @@
             }
             _ => {
                 diag.span_label(
-                    span,
+                    *span,
                     format!(
                         "{}requires that `{}` must outlive `{}`",
                         category.description(),
@@ -593,9 +600,9 @@
             }
         }
 
-        self.add_static_impl_trait_suggestion(infcx, &mut diag, fr, fr_name, outlived_fr);
+        self.add_static_impl_trait_suggestion(infcx, &mut diag, *fr, fr_name, *outlived_fr);
 
-        diag.buffer(errors_buffer);
+        diag
     }
 
     /// Adds a suggestion to errors where a `impl Trait` is returned.
@@ -704,8 +711,14 @@
             borrow_region,
             |r| self.provides_universal_region(r, borrow_region, outlived_region)
         );
-        let outlived_fr_name =
-            self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_region, &mut 1);
+
+        let mut renctx = RegionErrorNamingCtx::new();
+        let errctx = ErrorReportingCtx {
+            infcx, body, upvars, mir_def_id,
+            region_infcx: self,
+        };
+        let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
+
         (category, from_closure, span, outlived_fr_name)
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index 75a3162..6fa9426 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -1,5 +1,9 @@
 use std::fmt::{self, Display};
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
+
+use crate::borrow_check::nll::region_infer::{
+    RegionInferenceContext,
+    error_reporting::ErrorReportingCtx,
+};
 use crate::borrow_check::nll::universal_regions::DefiningTy;
 use crate::borrow_check::nll::ToRegionVid;
 use crate::borrow_check::Upvar;
@@ -13,29 +17,75 @@
 use rustc::ty::print::RegionHighlightMode;
 use rustc_errors::DiagnosticBuilder;
 use syntax::symbol::kw;
-use syntax_pos::Span;
-use syntax_pos::symbol::InternedString;
+use rustc_data_structures::fx::FxHashMap;
+use syntax_pos::{Span, symbol::InternedString};
 
-#[derive(Debug)]
+/// A name for a particular region used in emitting diagnostics. This name could be a generated
+/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
+#[derive(Debug, Clone)]
 crate struct RegionName {
+    /// The name of the region (interned).
     crate name: InternedString,
+    /// Where the region comes from.
     crate source: RegionNameSource,
 }
 
-#[derive(Debug)]
+/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
+/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`.
+/// This helps to print the right kinds of diagnostics.
+#[derive(Debug, Clone)]
 crate enum RegionNameSource {
+    /// A bound (not free) region that was substituted at the def site (not an HRTB).
     NamedEarlyBoundRegion(Span),
+    /// A free region that the user has a name (`'a`) for.
     NamedFreeRegion(Span),
+    /// The `'static` region.
     Static,
+    /// The free region corresponding to the environment of a closure.
     SynthesizedFreeEnvRegion(Span, String),
+    /// The region name corresponds to a region where the type annotation is completely missing
+    /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
     CannotMatchHirTy(Span, String),
+    /// The region name corresponds a reference that was found by traversing the type in the HIR.
     MatchedHirTy(Span),
+    /// A region name from the generics list of a struct/enum/union.
     MatchedAdtAndSegment(Span),
+    /// The region corresponding to a closure upvar.
     AnonRegionFromUpvar(Span, String),
+    /// The region corresponding to the return type of a closure.
     AnonRegionFromOutput(Span, String, String),
     AnonRegionFromYieldTy(Span, String),
 }
 
+/// Records region names that have been assigned before so that we can use the same ones in later
+/// diagnostics.
+#[derive(Debug, Clone)]
+crate struct RegionErrorNamingCtx {
+    /// Record the region names generated for each region in the given
+    /// MIR def so that we can reuse them later in help/error messages.
+    renctx: FxHashMap<RegionVid, RegionName>,
+
+    /// The counter for generating new region names.
+    counter: usize,
+}
+
+impl RegionErrorNamingCtx {
+    crate fn new() -> Self {
+        Self {
+            counter: 1,
+            renctx: FxHashMap::default(),
+        }
+    }
+
+    crate fn get(&self, region: &RegionVid) -> Option<&RegionName> {
+        self.renctx.get(region)
+    }
+
+    crate fn insert(&mut self, region: RegionVid, name: RegionName) {
+        self.renctx.insert(region, name);
+    }
+}
+
 impl RegionName {
     #[allow(dead_code)]
     crate fn was_named(&self) -> bool {
@@ -63,43 +113,40 @@
         self.name
     }
 
-    crate fn highlight_region_name(
-        &self,
-        diag: &mut DiagnosticBuilder<'_>
-    ) {
+    crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
         match &self.source {
-            RegionNameSource::NamedFreeRegion(span) |
-            RegionNameSource::NamedEarlyBoundRegion(span) => {
-                diag.span_label(
-                    *span,
-                    format!("lifetime `{}` defined here", self),
-                );
-            },
+            RegionNameSource::NamedFreeRegion(span)
+            | RegionNameSource::NamedEarlyBoundRegion(span) => {
+                diag.span_label(*span, format!("lifetime `{}` defined here", self));
+            }
             RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
                 diag.span_label(
                     *span,
                     format!("lifetime `{}` represents this closure's body", self),
                 );
                 diag.note(&note);
-            },
+            }
             RegionNameSource::CannotMatchHirTy(span, type_name) => {
                 diag.span_label(*span, format!("has type `{}`", type_name));
-            },
+            }
             RegionNameSource::MatchedHirTy(span) => {
                 diag.span_label(
                     *span,
                     format!("let's call the lifetime of this reference `{}`", self),
                 );
-            },
+            }
             RegionNameSource::MatchedAdtAndSegment(span) => {
                 diag.span_label(*span, format!("let's call this `{}`", self));
-            },
+            }
             RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
                 diag.span_label(
                     *span,
-                    format!("lifetime `{}` appears in the type of `{}`", self, upvar_name),
+                    format!(
+                        "lifetime `{}` appears in the type of `{}`",
+                        self, upvar_name
+                    ),
                 );
-            },
+            }
             RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => {
                 diag.span_label(
                     *span,
@@ -151,39 +198,49 @@
     /// and then return the name `'1` for us to use.
     crate fn give_region_a_name(
         &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        body: &Body<'tcx>,
-        upvars: &[Upvar],
-        mir_def_id: DefId,
+        errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
+        renctx: &mut RegionErrorNamingCtx,
         fr: RegionVid,
-        counter: &mut usize,
     ) -> Option<RegionName> {
-        debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);
+        let ErrorReportingCtx {
+            infcx, body, mir_def_id, upvars, ..
+        } = errctx;
+
+        debug!("give_region_a_name(fr={:?}, counter={:?})", fr, renctx.counter);
 
         assert!(self.universal_regions.is_universal_region(fr));
 
-        let value = self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter)
+        if let Some(value) = renctx.get(&fr) {
+            return Some(value.clone());
+        }
+
+        let value = self
+            .give_name_from_error_region(infcx.tcx, *mir_def_id, fr, renctx)
             .or_else(|| {
                 self.give_name_if_anonymous_region_appears_in_arguments(
-                    infcx, body, mir_def_id, fr, counter,
+                    infcx, body, *mir_def_id, fr, renctx,
                 )
             })
             .or_else(|| {
                 self.give_name_if_anonymous_region_appears_in_upvars(
-                    infcx.tcx, upvars, fr, counter,
+                    infcx.tcx, upvars, fr, renctx
                 )
             })
             .or_else(|| {
                 self.give_name_if_anonymous_region_appears_in_output(
-                    infcx, body, mir_def_id, fr, counter,
+                    infcx, body, *mir_def_id, fr, renctx,
                 )
             })
             .or_else(|| {
                 self.give_name_if_anonymous_region_appears_in_yield_ty(
-                    infcx, body, mir_def_id, fr, counter,
+                    infcx, body, *mir_def_id, fr, renctx,
                 )
             });
 
+        if let Some(ref value) = value {
+            renctx.insert(fr, value.clone());
+        }
+
         debug!("give_region_a_name: gave name {:?}", value);
         value
     }
@@ -197,7 +254,7 @@
         tcx: TyCtxt<'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
         let error_region = self.to_error_region(fr)?;
 
@@ -208,7 +265,7 @@
                     let span = self.get_named_span(tcx, error_region, ebr.name);
                     Some(RegionName {
                         name: ebr.name,
-                        source: RegionNameSource::NamedEarlyBoundRegion(span)
+                        source: RegionNameSource::NamedEarlyBoundRegion(span),
                     })
                 } else {
                     None
@@ -227,12 +284,10 @@
                         name,
                         source: RegionNameSource::NamedFreeRegion(span),
                     })
-                },
+                }
 
                 ty::BoundRegion::BrEnv => {
-                    let mir_hir_id = tcx.hir()
-                                        .as_local_hir_id(mir_def_id)
-                                        .expect("non-local mir");
+                    let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
                     let def_ty = self.universal_regions.defining_ty;
 
                     if let DefiningTy::Closure(def_id, substs) = def_ty {
@@ -243,7 +298,7 @@
                         } else {
                             bug!("Closure is not defined by a closure expr");
                         };
-                        let region_name = self.synthesize_region_name(counter);
+                        let region_name = self.synthesize_region_name(renctx);
 
                         let closure_kind_ty = substs.closure_kind_ty(def_id, tcx);
                         let note = match closure_kind_ty.to_opt_closure_kind() {
@@ -265,7 +320,7 @@
                             name: region_name,
                             source: RegionNameSource::SynthesizedFreeEnvRegion(
                                 args_span,
-                                note.to_string()
+                                note.to_string(),
                             ),
                         })
                     } else {
@@ -335,7 +390,7 @@
         body: &Body<'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
         let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
         let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
@@ -349,12 +404,12 @@
             fr,
             arg_ty,
             argument_index,
-            counter,
+            renctx,
         ) {
             return Some(region_name);
         }
 
-        self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, counter)
+        self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, renctx)
     }
 
     fn give_name_if_we_can_match_hir_ty_from_argument(
@@ -365,7 +420,7 @@
         needle_fr: RegionVid,
         argument_ty: Ty<'tcx>,
         argument_index: usize,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
         let mir_hir_id = infcx.tcx.hir().as_local_hir_id(mir_def_id)?;
         let fn_decl = infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
@@ -379,7 +434,7 @@
                 body,
                 needle_fr,
                 argument_ty,
-                counter,
+                renctx,
             ),
 
             _ => self.give_name_if_we_can_match_hir_ty(
@@ -387,7 +442,7 @@
                 needle_fr,
                 argument_ty,
                 argument_hir_ty,
-                counter,
+                renctx,
             ),
         }
     }
@@ -409,10 +464,11 @@
         body: &Body<'tcx>,
         needle_fr: RegionVid,
         argument_ty: Ty<'tcx>,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
+        let counter = renctx.counter;
         let mut highlight = RegionHighlightMode::default();
-        highlight.highlighting_region_vid(needle_fr, *counter);
+        highlight.highlighting_region_vid(needle_fr, counter);
         let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)).0;
 
         debug!(
@@ -428,7 +484,7 @@
                 // This counter value will already have been used, so this function will increment
                 // it so the next value will be used next and return the region name that would
                 // have been used.
-                name: self.synthesize_region_name(counter),
+                name: self.synthesize_region_name(renctx),
                 source: RegionNameSource::CannotMatchHirTy(span, type_name),
             })
         } else {
@@ -455,7 +511,7 @@
     /// type. Once we find that, we can use the span of the `hir::Ty`
     /// to add the highlight.
     ///
-    /// This is a somewhat imperfect process, so long the way we also
+    /// This is a somewhat imperfect process, so along the way we also
     /// keep track of the **closest** type we've found. If we fail to
     /// find the exact `&` or `'_` to highlight, then we may fall back
     /// to highlighting that closest type instead.
@@ -465,7 +521,7 @@
         needle_fr: RegionVid,
         argument_ty: Ty<'tcx>,
         argument_hir_ty: &hir::Ty,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
         let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> =
             &mut vec![(argument_ty, argument_hir_ty)];
@@ -483,7 +539,7 @@
                     hir::TyKind::Rptr(_lifetime, referent_hir_ty),
                 ) => {
                     if region.to_region_vid() == needle_fr {
-                        let region_name = self.synthesize_region_name(counter);
+                        let region_name = self.synthesize_region_name(renctx);
 
                         // Just grab the first character, the `&`.
                         let source_map = tcx.sess.source_map();
@@ -515,7 +571,7 @@
                                 substs,
                                 needle_fr,
                                 last_segment,
-                                counter,
+                                renctx,
                                 search_stack,
                             ) {
                                 return Some(name);
@@ -559,18 +615,19 @@
         substs: SubstsRef<'tcx>,
         needle_fr: RegionVid,
         last_segment: &'hir hir::PathSegment,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
         search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
     ) -> Option<RegionName> {
         // Did the user give explicit arguments? (e.g., `Foo<..>`)
         let args = last_segment.args.as_ref()?;
-        let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
+        let lifetime =
+            self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
         match lifetime.name {
             hir::LifetimeName::Param(_)
             | hir::LifetimeName::Error
             | hir::LifetimeName::Static
             | hir::LifetimeName::Underscore => {
-                let region_name = self.synthesize_region_name(counter);
+                let region_name = self.synthesize_region_name(renctx);
                 let ampersand_span = lifetime.span;
                 Some(RegionName {
                     name: region_name,
@@ -657,12 +714,12 @@
         tcx: TyCtxt<'tcx>,
         upvars: &[Upvar],
         fr: RegionVid,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
         let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
         let (upvar_name, upvar_span) =
             self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index);
-        let region_name = self.synthesize_region_name(counter);
+        let region_name = self.synthesize_region_name(renctx);
 
         Some(RegionName {
             name: region_name,
@@ -680,7 +737,7 @@
         body: &Body<'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
         let tcx = infcx.tcx;
 
@@ -694,7 +751,7 @@
         }
 
         let mut highlight = RegionHighlightMode::default();
-        highlight.highlighting_region_vid(fr, *counter);
+        highlight.highlighting_region_vid(fr, renctx.counter);
         let type_name = infcx.extract_type_name(&return_ty, Some(highlight)).0;
 
         let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
@@ -725,11 +782,11 @@
             // This counter value will already have been used, so this function will increment it
             // so the next value will be used next and return the region name that would have been
             // used.
-            name: self.synthesize_region_name(counter),
+            name: self.synthesize_region_name(renctx),
             source: RegionNameSource::AnonRegionFromOutput(
                 return_span,
                 mir_description.to_string(),
-                type_name
+                type_name,
             ),
         })
     }
@@ -740,7 +797,7 @@
         body: &Body<'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
-        counter: &mut usize,
+        renctx: &mut RegionErrorNamingCtx,
     ) -> Option<RegionName> {
         // Note: generators from `async fn` yield `()`, so we don't have to
         // worry about them here.
@@ -757,7 +814,7 @@
         }
 
         let mut highlight = RegionHighlightMode::default();
-        highlight.highlighting_region_vid(fr, *counter);
+        highlight.highlighting_region_vid(fr, renctx.counter);
         let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)).0;
 
         let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir");
@@ -780,16 +837,15 @@
         );
 
         Some(RegionName {
-            name: self.synthesize_region_name(counter),
+            name: self.synthesize_region_name(renctx),
             source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
         })
     }
 
-    /// Creates a synthetic region named `'1`, incrementing the
-    /// counter.
-    fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
-        let c = *counter;
-        *counter += 1;
+    /// Creates a synthetic region named `'1`, incrementing the counter.
+    fn synthesize_region_name(&self, renctx: &mut RegionErrorNamingCtx) -> InternedString {
+        let c = renctx.counter;
+        renctx.counter += 1;
 
         InternedString::intern(&format!("'{:?}", c))
     }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 4038872..78e7943 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -1,15 +1,20 @@
-use super::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph;
-use crate::borrow_check::nll::constraints::{
-    ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
+use std::rc::Rc;
+
+use crate::borrow_check::nll::{
+    constraints::{
+        graph::NormalConstraintGraph,
+        ConstraintSccIndex,
+        OutlivesConstraint,
+        OutlivesConstraintSet,
+    },
+    member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
+    region_infer::values::{
+        PlaceholderIndices, RegionElement, ToElementIndex
+    },
+    type_check::{free_region_relations::UniversalRegionRelations, Locations},
 };
-use crate::borrow_check::nll::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
-use crate::borrow_check::nll::region_infer::values::{
-    PlaceholderIndices, RegionElement, ToElementIndex,
-};
-use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
-use crate::borrow_check::nll::type_check::Locations;
 use crate::borrow_check::Upvar;
+
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryOutlivesConstraint;
 use rustc::infer::opaque_types;
@@ -31,16 +36,16 @@
 use rustc_errors::{Diagnostic, DiagnosticBuilder};
 use syntax_pos::Span;
 
-use std::rc::Rc;
+crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx};
+use self::values::{LivenessValues, RegionValueElements, RegionValues};
+use super::universal_regions::UniversalRegions;
+use super::ToRegionVid;
 
 mod dump_mir;
 mod error_reporting;
-crate use self::error_reporting::{RegionName, RegionNameSource};
 mod graphviz;
-pub mod values;
-use self::values::{LivenessValues, RegionValueElements, RegionValues};
 
-use super::ToRegionVid;
+pub mod values;
 
 pub struct RegionInferenceContext<'tcx> {
     /// Contains the definition for every region variable. Region
@@ -487,6 +492,12 @@
             errors_buffer,
         );
 
+        // If we produce any errors, we keep track of the names of all regions, so that we can use
+        // the same error names in any suggestions we produce. Note that we need names to be unique
+        // across different errors for the same MIR def so that we can make suggestions that fix
+        // multiple problems.
+        let mut region_naming = RegionErrorNamingCtx::new();
+
         self.check_universal_regions(
             infcx,
             body,
@@ -494,6 +505,7 @@
             mir_def_id,
             outlives_requirements.as_mut(),
             errors_buffer,
+            &mut region_naming,
         );
 
         self.check_member_constraints(infcx, mir_def_id, errors_buffer);
@@ -1312,6 +1324,7 @@
         mir_def_id: DefId,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut Vec<Diagnostic>,
+        region_naming: &mut RegionErrorNamingCtx,
     ) {
         for (fr, fr_definition) in self.definitions.iter_enumerated() {
             match fr_definition.origin {
@@ -1327,6 +1340,7 @@
                         fr,
                         &mut propagated_outlives_requirements,
                         errors_buffer,
+                        region_naming,
                     );
                 }
 
@@ -1358,6 +1372,7 @@
         longer_fr: RegionVid,
         propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut Vec<Diagnostic>,
+        region_naming: &mut RegionErrorNamingCtx,
     ) {
         debug!("check_universal_region(fr={:?})", longer_fr);
 
@@ -1385,6 +1400,7 @@
                 mir_def_id,
                 propagated_outlives_requirements,
                 errors_buffer,
+                region_naming,
             );
             return;
         }
@@ -1401,8 +1417,13 @@
                 mir_def_id,
                 propagated_outlives_requirements,
                 errors_buffer,
+                region_naming,
             ) {
                 // continuing to iterate just reports more errors than necessary
+                //
+                // FIXME It would also allow us to report more Outlives Suggestions, though, so
+                // it's not clear that that's a bad thing. Somebody should try commenting out this
+                // line and see it is actually a regression.
                 return;
             }
         }
@@ -1418,6 +1439,7 @@
         mir_def_id: DefId,
         propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut Vec<Diagnostic>,
+        region_naming: &mut RegionErrorNamingCtx,
     ) -> Option<ErrorReported> {
         // If it is known that `fr: o`, carry on.
         if self.universal_region_relations.outlives(longer_fr, shorter_fr) {
@@ -1466,7 +1488,18 @@
         //
         // Note: in this case, we use the unapproximated regions to report the
         // error. This gives better error messages in some cases.
-        self.report_error(body, upvars, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
+        let db = self.report_error(
+            body,
+            upvars,
+            infcx,
+            mir_def_id,
+            longer_fr,
+            shorter_fr,
+            region_naming,
+        );
+
+        db.buffer(errors_buffer);
+
         Some(ErrorReported)
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index da1f64b..62bff34 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -421,107 +421,104 @@
     ) -> PlaceTy<'tcx> {
         debug!("sanitize_place: {:?}", place);
 
-        place.iterate(|place_base, place_projection| {
-            let mut place_ty = match place_base {
-                PlaceBase::Local(index) =>
-                    PlaceTy::from_ty(self.body.local_decls[*index].ty),
-                PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
-                    let sty = self.sanitize_type(place, sty);
-                    let check_err =
-                        |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
-                         place: &Place<'tcx>,
-                         ty,
-                         sty| {
-                            if let Err(terr) = verifier.cx.eq_types(
-                                sty,
-                                ty,
-                                location.to_locations(),
-                                ConstraintCategory::Boring,
-                            ) {
-                                span_mirbug!(
-                                verifier,
-                                place,
-                                "bad promoted type ({:?}: {:?}): {:?}",
-                                ty,
-                                sty,
-                                terr
-                            );
-                            };
+        let mut place_ty = match &place.base {
+            PlaceBase::Local(index) =>
+                PlaceTy::from_ty(self.body.local_decls[*index].ty),
+            PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
+                let sty = self.sanitize_type(place, sty);
+                let check_err =
+                    |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
+                     place: &Place<'tcx>,
+                     ty,
+                     sty| {
+                        if let Err(terr) = verifier.cx.eq_types(
+                            sty,
+                            ty,
+                            location.to_locations(),
+                            ConstraintCategory::Boring,
+                        ) {
+                            span_mirbug!(
+                            verifier,
+                            place,
+                            "bad promoted type ({:?}: {:?}): {:?}",
+                            ty,
+                            sty,
+                            terr
+                        );
                         };
-                    match kind {
-                        StaticKind::Promoted(promoted, _) => {
-                            if !self.errors_reported {
-                                let promoted_body = &self.promoted[*promoted];
-                                self.sanitize_promoted(promoted_body, location);
+                    };
+                match kind {
+                    StaticKind::Promoted(promoted, _) => {
+                        if !self.errors_reported {
+                            let promoted_body = &self.promoted[*promoted];
+                            self.sanitize_promoted(promoted_body, location);
 
-                                let promoted_ty = promoted_body.return_ty();
-                                check_err(self, place, promoted_ty, sty);
-                            }
-                        }
-                        StaticKind::Static => {
-                            let ty = self.tcx().type_of(*def_id);
-                            let ty = self.cx.normalize(ty, location);
-
-                            check_err(self, place, ty, sty);
+                            let promoted_ty = promoted_body.return_ty();
+                            check_err(self, place, promoted_ty, sty);
                         }
                     }
-                    PlaceTy::from_ty(sty)
-                }
-            };
+                    StaticKind::Static => {
+                        let ty = self.tcx().type_of(*def_id);
+                        let ty = self.cx.normalize(ty, location);
 
-            // FIXME use place_projection.is_empty() when is available
-            if place.projection.is_none() {
-                if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
-                    let is_promoted = match place {
-                        Place {
-                            base: PlaceBase::Static(box Static {
-                                kind: StaticKind::Promoted(..),
-                                ..
-                            }),
-                            projection: None,
-                        } => true,
-                        _ => false,
+                        check_err(self, place, ty, sty);
+                    }
+                }
+                PlaceTy::from_ty(sty)
+            }
+        };
+
+        if place.projection.is_empty() {
+            if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
+                let is_promoted = match place {
+                    Place {
+                        base: PlaceBase::Static(box Static {
+                            kind: StaticKind::Promoted(..),
+                            ..
+                        }),
+                        projection: box [],
+                    } => true,
+                    _ => false,
+                };
+
+                if !is_promoted {
+                    let tcx = self.tcx();
+                    let trait_ref = ty::TraitRef {
+                        def_id: tcx.lang_items().copy_trait().unwrap(),
+                        substs: tcx.mk_substs_trait(place_ty.ty, &[]),
                     };
 
-                    if !is_promoted {
-                        let tcx = self.tcx();
-                        let trait_ref = ty::TraitRef {
-                            def_id: tcx.lang_items().copy_trait().unwrap(),
-                            substs: tcx.mk_substs_trait(place_ty.ty, &[]),
-                        };
-
-                        // In order to have a Copy operand, the type T of the
-                        // value must be Copy. Note that we prove that T: Copy,
-                        // rather than using the `is_copy_modulo_regions`
-                        // test. This is important because
-                        // `is_copy_modulo_regions` ignores the resulting region
-                        // obligations and assumes they pass. This can result in
-                        // bounds from Copy impls being unsoundly ignored (e.g.,
-                        // #29149). Note that we decide to use Copy before knowing
-                        // whether the bounds fully apply: in effect, the rule is
-                        // that if a value of some type could implement Copy, then
-                        // it must.
-                        self.cx.prove_trait_ref(
-                            trait_ref,
-                            location.to_locations(),
-                            ConstraintCategory::CopyBound,
-                        );
-                    }
+                    // To have a `Copy` operand, the type `T` of the
+                    // value must be `Copy`. Note that we prove that `T: Copy`,
+                    // rather than using the `is_copy_modulo_regions`
+                    // test. This is important because
+                    // `is_copy_modulo_regions` ignores the resulting region
+                    // obligations and assumes they pass. This can result in
+                    // bounds from `Copy` impls being unsoundly ignored (e.g.,
+                    // #29149). Note that we decide to use `Copy` before knowing
+                    // whether the bounds fully apply: in effect, the rule is
+                    // that if a value of some type could implement `Copy`, then
+                    // it must.
+                    self.cx.prove_trait_ref(
+                        trait_ref,
+                        location.to_locations(),
+                        ConstraintCategory::CopyBound,
+                    );
                 }
             }
+        }
 
-            for proj in place_projection {
-                if place_ty.variant_index.is_none() {
-                    if place_ty.ty.references_error() {
-                        assert!(self.errors_reported);
-                        return PlaceTy::from_ty(self.tcx().types.err);
-                    }
+        for elem in place.projection.iter() {
+            if place_ty.variant_index.is_none() {
+                if place_ty.ty.references_error() {
+                    assert!(self.errors_reported);
+                    return PlaceTy::from_ty(self.tcx().types.err);
                 }
-                place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
             }
+            place_ty = self.sanitize_projection(place_ty, elem, place, location)
+        }
 
-            place_ty
-        })
+        place_ty
     }
 
     fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) {
@@ -1346,7 +1343,7 @@
         debug!("check_stmt: {:?}", stmt);
         let tcx = self.tcx();
         match stmt.kind {
-            StatementKind::Assign(ref place, ref rv) => {
+            StatementKind::Assign(box(ref place, ref rv)) => {
                 // Assignments to temporaries are not "interesting";
                 // they are not caused by the user, but rather artifacts
                 // of lowering. Assignments to other sorts of places *are* interesting
@@ -1354,7 +1351,7 @@
                 let category = match *place {
                     Place {
                         base: PlaceBase::Local(RETURN_PLACE),
-                        projection: None,
+                        projection: box [],
                     } => if let BorrowCheckContext {
                         universal_regions:
                             UniversalRegions {
@@ -1373,7 +1370,7 @@
                     },
                     Place {
                         base: PlaceBase::Local(l),
-                        projection: None,
+                        projection: box [],
                     } if !body.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
@@ -1453,7 +1450,7 @@
                     );
                 };
             }
-            StatementKind::AscribeUserType(ref place, variance, box ref projection) => {
+            StatementKind::AscribeUserType(box(ref place, ref projection), variance) => {
                 let place_ty = place.ty(body, tcx).ty;
                 if let Err(terr) = self.relate_type_and_user_type(
                     place_ty,
@@ -1660,7 +1657,7 @@
                 let category = match *dest {
                     Place {
                         base: PlaceBase::Local(RETURN_PLACE),
-                        projection: None,
+                        projection: box [],
                     } => {
                         if let BorrowCheckContext {
                             universal_regions:
@@ -1682,7 +1679,7 @@
                     }
                     Place {
                         base: PlaceBase::Local(l),
-                        projection: None,
+                        projection: box [],
                     } if !body.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
@@ -2416,19 +2413,21 @@
         // *p`, where the `p` has type `&'b mut Foo`, for example, we
         // need to ensure that `'b: 'a`.
 
-        let mut borrowed_projection = &borrowed_place.projection;
-
         debug!(
             "add_reborrow_constraint({:?}, {:?}, {:?})",
             location, borrow_region, borrowed_place
         );
-        while let Some(box proj) = borrowed_projection {
-            debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection);
 
-            match proj.elem {
+        let mut cursor = &*borrowed_place.projection;
+        while let [proj_base @ .., elem] = cursor {
+            cursor = proj_base;
+
+            debug!("add_reborrow_constraint - iteration {:?}", elem);
+
+            match elem {
                 ProjectionElem::Deref => {
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, body, tcx).ty;
+                    let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
 
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.sty {
@@ -2490,10 +2489,6 @@
                     // other field access
                 }
             }
-
-            // The "propagate" case. We need to check that our base is valid
-            // for the borrow's lifetime.
-            borrowed_projection = &proj.base;
         }
     }
 
diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs
index 5caba63..411fa5b 100644
--- a/src/librustc_mir/borrow_check/place_ext.rs
+++ b/src/librustc_mir/borrow_check/place_ext.rs
@@ -25,55 +25,54 @@
         body: &Body<'tcx>,
         locals_state_at_exit: &LocalsStateAtExit,
     ) -> bool {
-        self.iterate(|place_base, place_projection| {
-            let ignore = match place_base {
-                // If a local variable is immutable, then we only need to track borrows to guard
-                // against two kinds of errors:
-                // * The variable being dropped while still borrowed (e.g., because the fn returns
-                //   a reference to a local variable)
-                // * The variable being moved while still borrowed
-                //
-                // In particular, the variable cannot be mutated -- the "access checks" will fail --
-                // so we don't have to worry about mutation while borrowed.
-                PlaceBase::Local(index) => {
-                    match locals_state_at_exit {
-                        LocalsStateAtExit::AllAreInvalidated => false,
-                        LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
-                            let ignore = !has_storage_dead_or_moved.contains(*index) &&
-                                body.local_decls[*index].mutability == Mutability::Not;
-                            debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
-                            ignore
-                        }
-                    }
-                }
-                PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
-                    false,
-                PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
-                    tcx.is_mutable_static(*def_id)
-                }
-            };
-
-            for proj in place_projection {
-                if proj.elem == ProjectionElem::Deref {
-                    let ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
-                    match ty.sty {
-                        // For both derefs of raw pointers and `&T`
-                        // references, the original path is `Copy` and
-                        // therefore not significant.  In particular,
-                        // there is nothing the user can do to the
-                        // original path that would invalidate the
-                        // newly created reference -- and if there
-                        // were, then the user could have copied the
-                        // original path into a new variable and
-                        // borrowed *that* one, leaving the original
-                        // path unborrowed.
-                        ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true,
-                        _ => {}
+        let ignore = match self.base {
+            // If a local variable is immutable, then we only need to track borrows to guard
+            // against two kinds of errors:
+            // * The variable being dropped while still borrowed (e.g., because the fn returns
+            //   a reference to a local variable)
+            // * The variable being moved while still borrowed
+            //
+            // In particular, the variable cannot be mutated -- the "access checks" will fail --
+            // so we don't have to worry about mutation while borrowed.
+            PlaceBase::Local(index) => {
+                match locals_state_at_exit {
+                    LocalsStateAtExit::AllAreInvalidated => false,
+                    LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
+                        let ignore = !has_storage_dead_or_moved.contains(index) &&
+                            body.local_decls[index].mutability == Mutability::Not;
+                        debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
+                        ignore
                     }
                 }
             }
+            PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
+                false,
+            PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
+                tcx.is_mutable_static(def_id)
+            }
+        };
 
-            ignore
-        })
+        for (i, elem) in self.projection.iter().enumerate() {
+            let proj_base = &self.projection[..i];
+
+            if *elem == ProjectionElem::Deref {
+                let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
+                if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = ty.sty {
+                    // For both derefs of raw pointers and `&T`
+                    // references, the original path is `Copy` and
+                    // therefore not significant.  In particular,
+                    // there is nothing the user can do to the
+                    // original path that would invalidate the
+                    // newly created reference -- and if there
+                    // were, then the user could have copied the
+                    // original path into a new variable and
+                    // borrowed *that* one, leaving the original
+                    // path unborrowed.
+                    return true;
+                }
+            }
+        }
+
+        ignore
     }
 }
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 4f46917..dafa0b6 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -3,8 +3,7 @@
 use crate::borrow_check::{Deep, Shallow, AccessDepth};
 use rustc::hir;
 use rustc::mir::{
-    Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter,
-    StaticKind,
+    Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
 };
 use rustc::ty::{self, TyCtxt};
 use std::cmp::max;
@@ -67,39 +66,35 @@
     // it's so common that it's a speed win to check for it first.
     if let Place {
         base: PlaceBase::Local(l1),
-        projection: None,
+        projection: box [],
     } = borrow_place {
         if let PlaceRef {
             base: PlaceBase::Local(l2),
-            projection: None,
+            projection: [],
         } = access_place {
             return l1 == l2;
         }
     }
 
-    borrow_place.iterate(|borrow_base, borrow_projections| {
-        access_place.iterate(|access_base, access_projections| {
-            place_components_conflict(
-                tcx,
-                param_env,
-                body,
-                (borrow_base, borrow_projections),
-                borrow_kind,
-                (access_base, access_projections),
-                access,
-                bias,
-            )
-        })
-    })
+    place_components_conflict(
+        tcx,
+        param_env,
+        body,
+        borrow_place,
+        borrow_kind,
+        access_place,
+        access,
+        bias,
+    )
 }
 
 fn place_components_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
-    borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
+    borrow_place: &Place<'tcx>,
     borrow_kind: BorrowKind,
-    access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
+    access_place: PlaceRef<'_, 'tcx>,
     access: AccessDepth,
     bias: PlaceConflictBias,
 ) -> bool {
@@ -145,8 +140,8 @@
     //    and either equal or disjoint.
     //  - If we did run out of access, the borrow can access a part of it.
 
-    let borrow_base = borrow_projections.0;
-    let access_base = access_projections.0;
+    let borrow_base = &borrow_place.base;
+    let access_base = access_place.base;
 
     match place_base_conflict(tcx, param_env, borrow_base, access_base) {
         Overlap::Arbitrary => {
@@ -163,147 +158,157 @@
         }
     }
 
-    let mut borrow_projections = borrow_projections.1;
-    let mut access_projections = access_projections.1;
+    // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
+    for (i, (borrow_c, access_c)) in
+        borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate()
+    {
+        debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
+        let borrow_proj_base = &borrow_place.projection[..i];
 
-    loop {
-        // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
-        if let Some(borrow_c) = borrow_projections.next() {
-            debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
+        debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
 
-            if let Some(access_c) = access_projections.next() {
-                debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
-
-                // Borrow and access path both have more components.
+        // Borrow and access path both have more components.
+        //
+        // Examples:
+        //
+        // - borrow of `a.(...)`, access to `a.(...)`
+        // - borrow of `a.(...)`, access to `b.(...)`
+        //
+        // Here we only see the components we have checked so
+        // far (in our examples, just the first component). We
+        // check whether the components being borrowed vs
+        // accessed are disjoint (as in the second example,
+        // but not the first).
+        match place_projection_conflict(
+            tcx,
+            body,
+            borrow_base,
+            borrow_proj_base,
+            borrow_c,
+            access_c,
+            bias,
+        ) {
+            Overlap::Arbitrary => {
+                // We have encountered different fields of potentially
+                // the same union - the borrow now partially overlaps.
                 //
-                // Examples:
+                // There is no *easy* way of comparing the fields
+                // further on, because they might have different types
+                // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
+                // `.y` come from different structs).
                 //
-                // - borrow of `a.(...)`, access to `a.(...)`
-                // - borrow of `a.(...)`, access to `b.(...)`
-                //
-                // Here we only see the components we have checked so
-                // far (in our examples, just the first component). We
-                // check whether the components being borrowed vs
-                // accessed are disjoint (as in the second example,
-                // but not the first).
-                match place_projection_conflict(tcx, body, borrow_base, borrow_c, access_c, bias) {
-                    Overlap::Arbitrary => {
-                        // We have encountered different fields of potentially
-                        // the same union - the borrow now partially overlaps.
-                        //
-                        // There is no *easy* way of comparing the fields
-                        // further on, because they might have different types
-                        // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
-                        // `.y` come from different structs).
-                        //
-                        // We could try to do some things here - e.g., count
-                        // dereferences - but that's probably not a good
-                        // idea, at least for now, so just give up and
-                        // report a conflict. This is unsafe code anyway so
-                        // the user could always use raw pointers.
-                        debug!("borrow_conflicts_with_place: arbitrary -> conflict");
-                        return true;
-                    }
-                    Overlap::EqualOrDisjoint => {
-                        // This is the recursive case - proceed to the next element.
-                    }
-                    Overlap::Disjoint => {
-                        // We have proven the borrow disjoint - further
-                        // projections will remain disjoint.
-                        debug!("borrow_conflicts_with_place: disjoint");
-                        return false;
-                    }
-                }
-            } else {
-                // Borrow path is longer than the access path. Examples:
-                //
-                // - borrow of `a.b.c`, access to `a.b`
-                //
-                // Here, we know that the borrow can access a part of
-                // our place. This is a conflict if that is a part our
-                // access cares about.
-
-                let base = &borrow_c.base;
-                let elem = &borrow_c.elem;
-                let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty;
-
-                match (elem, &base_ty.sty, access) {
-                    (_, _, Shallow(Some(ArtificialField::ArrayLength)))
-                    | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
-                        // The array length is like  additional fields on the
-                        // type; it does not overlap any existing data there.
-                        // Furthermore, if cannot actually be a prefix of any
-                        // borrowed place (at least in MIR as it is currently.)
-                        //
-                        // e.g., a (mutable) borrow of `a[5]` while we read the
-                        // array length of `a`.
-                        debug!("borrow_conflicts_with_place: implicit field");
-                        return false;
-                    }
-
-                    (ProjectionElem::Deref, _, Shallow(None)) => {
-                        // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
-                        // prefix thereof - the shallow access can't touch anything behind
-                        // the pointer.
-                        debug!("borrow_conflicts_with_place: shallow access behind ptr");
-                        return false;
-                    }
-                    (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
-                        // Shouldn't be tracked
-                        bug!("Tracking borrow behind shared reference.");
-                    }
-                    (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
-                        // Values behind a mutable reference are not access either by dropping a
-                        // value, or by StorageDead
-                        debug!("borrow_conflicts_with_place: drop access behind ptr");
-                        return false;
-                    }
-
-                    (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
-                        // Drop can read/write arbitrary projections, so places
-                        // conflict regardless of further projections.
-                        if def.has_dtor(tcx) {
-                            return true;
-                        }
-                    }
-
-                    (ProjectionElem::Deref, _, Deep)
-                    | (ProjectionElem::Deref, _, AccessDepth::Drop)
-                    | (ProjectionElem::Field { .. }, _, _)
-                    | (ProjectionElem::Index { .. }, _, _)
-                    | (ProjectionElem::ConstantIndex { .. }, _, _)
-                    | (ProjectionElem::Subslice { .. }, _, _)
-                    | (ProjectionElem::Downcast { .. }, _, _) => {
-                        // Recursive case. This can still be disjoint on a
-                        // further iteration if this a shallow access and
-                        // there's a deref later on, e.g., a borrow
-                        // of `*x.y` while accessing `x`.
-                    }
-                }
-            }
-        } else {
-            // Borrow path ran out but access path may not
-            // have. Examples:
-            //
-            // - borrow of `a.b`, access to `a.b.c`
-            // - borrow of `a.b`, access to `a.b`
-            //
-            // In the first example, where we didn't run out of
-            // access, the borrow can access all of our place, so we
-            // have a conflict.
-            //
-            // If the second example, where we did, then we still know
-            // that the borrow can access a *part* of our place that
-            // our access cares about, so we still have a conflict.
-            if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() {
-                debug!("borrow_conflicts_with_place: shallow borrow");
-                return false;
-            } else {
-                debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
+                // We could try to do some things here - e.g., count
+                // dereferences - but that's probably not a good
+                // idea, at least for now, so just give up and
+                // report a conflict. This is unsafe code anyway so
+                // the user could always use raw pointers.
+                debug!("borrow_conflicts_with_place: arbitrary -> conflict");
                 return true;
             }
+            Overlap::EqualOrDisjoint => {
+                // This is the recursive case - proceed to the next element.
+            }
+            Overlap::Disjoint => {
+                // We have proven the borrow disjoint - further
+                // projections will remain disjoint.
+                debug!("borrow_conflicts_with_place: disjoint");
+                return false;
+            }
         }
     }
+
+    if borrow_place.projection.len() > access_place.projection.len() {
+        for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
+        {
+            // Borrow path is longer than the access path. Examples:
+            //
+            // - borrow of `a.b.c`, access to `a.b`
+            //
+            // Here, we know that the borrow can access a part of
+            // our place. This is a conflict if that is a part our
+            // access cares about.
+
+            let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
+            let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty;
+
+            match (elem, &base_ty.sty, access) {
+                (_, _, Shallow(Some(ArtificialField::ArrayLength)))
+                | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
+                    // The array length is like  additional fields on the
+                    // type; it does not overlap any existing data there.
+                    // Furthermore, if cannot actually be a prefix of any
+                    // borrowed place (at least in MIR as it is currently.)
+                    //
+                    // e.g., a (mutable) borrow of `a[5]` while we read the
+                    // array length of `a`.
+                    debug!("borrow_conflicts_with_place: implicit field");
+                    return false;
+                }
+
+                (ProjectionElem::Deref, _, Shallow(None)) => {
+                    // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
+                    // prefix thereof - the shallow access can't touch anything behind
+                    // the pointer.
+                    debug!("borrow_conflicts_with_place: shallow access behind ptr");
+                    return false;
+                }
+                (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
+                    // Shouldn't be tracked
+                    bug!("Tracking borrow behind shared reference.");
+                }
+                (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
+                    // Values behind a mutable reference are not access either by dropping a
+                    // value, or by StorageDead
+                    debug!("borrow_conflicts_with_place: drop access behind ptr");
+                    return false;
+                }
+
+                (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
+                    // Drop can read/write arbitrary projections, so places
+                    // conflict regardless of further projections.
+                    if def.has_dtor(tcx) {
+                        return true;
+                    }
+                }
+
+                (ProjectionElem::Deref, _, Deep)
+                | (ProjectionElem::Deref, _, AccessDepth::Drop)
+                | (ProjectionElem::Field { .. }, _, _)
+                | (ProjectionElem::Index { .. }, _, _)
+                | (ProjectionElem::ConstantIndex { .. }, _, _)
+                | (ProjectionElem::Subslice { .. }, _, _)
+                | (ProjectionElem::Downcast { .. }, _, _) => {
+                    // Recursive case. This can still be disjoint on a
+                    // further iteration if this a shallow access and
+                    // there's a deref later on, e.g., a borrow
+                    // of `*x.y` while accessing `x`.
+                }
+            }
+        }
+    }
+
+    // Borrow path ran out but access path may not
+    // have. Examples:
+    //
+    // - borrow of `a.b`, access to `a.b.c`
+    // - borrow of `a.b`, access to `a.b`
+    //
+    // In the first example, where we didn't run out of
+    // access, the borrow can access all of our place, so we
+    // have a conflict.
+    //
+    // If the second example, where we did, then we still know
+    // that the borrow can access a *part* of our place that
+    // our access cares about, so we still have a conflict.
+    if borrow_kind == BorrowKind::Shallow
+        && borrow_place.projection.len() < access_place.projection.len()
+    {
+        debug!("borrow_conflicts_with_place: shallow borrow");
+        false
+    } else {
+        debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
+        true
+    }
 }
 
 // Given that the bases of `elem1` and `elem2` are always either equal
@@ -381,11 +386,12 @@
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     pi1_base: &PlaceBase<'tcx>,
-    pi1: &Projection<'tcx>,
-    pi2: &Projection<'tcx>,
+    pi1_proj_base: &[PlaceElem<'tcx>],
+    pi1_elem: &PlaceElem<'tcx>,
+    pi2_elem: &PlaceElem<'tcx>,
     bias: PlaceConflictBias,
 ) -> Overlap {
-    match (&pi1.elem, &pi2.elem) {
+    match (pi1_elem, pi2_elem) {
         (ProjectionElem::Deref, ProjectionElem::Deref) => {
             // derefs (e.g., `*x` vs. `*x`) - recur.
             debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
@@ -397,7 +403,7 @@
                 debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
                 Overlap::EqualOrDisjoint
             } else {
-                let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty;
+                let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
                 match ty.sty {
                     ty::Adt(def, _) if def.is_union() => {
                         // Different fields of a union, we are basically stuck.
@@ -493,7 +499,7 @@
             // element (like -1 in Python) and `min_length` the first.
             // Therefore, `min_length - offset_from_end` gives the minimal possible
             // offset from the beginning
-            if *offset_from_begin >= min_length - offset_from_end {
+            if *offset_from_begin >= *min_length - *offset_from_end {
                 debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
                 Overlap::EqualOrDisjoint
             } else {
@@ -538,8 +544,8 @@
         | (ProjectionElem::Subslice { .. }, _)
         | (ProjectionElem::Downcast(..), _) => bug!(
             "mismatched projections in place_element_conflict: {:?} and {:?}",
-            pi1,
-            pi2
+            pi1_elem,
+            pi2_elem
         ),
     }
 }
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index 4c6be23..0a268ec 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -19,17 +19,9 @@
 
 impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
     fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
-        let mut cursor = other.projection;
-        loop {
-            if self.projection == cursor {
-                return self.base == other.base;
-            }
-
-            match cursor {
-                None => return false,
-                Some(proj) => cursor = &proj.base,
-            }
-        }
+        self.base == other.base
+            && self.projection.len() <= other.projection.len()
+            && self.projection == &other.projection[..self.projection.len()]
     }
 }
 
@@ -81,112 +73,113 @@
         // downcasts here, but may return a base of a downcast).
 
         'cursor: loop {
-            let proj = match &cursor {
+            match &cursor {
                 PlaceRef {
                     base: PlaceBase::Local(_),
-                    projection: None,
+                    projection: [],
                 }
                 | // search yielded this leaf
                 PlaceRef {
                     base: PlaceBase::Static(_),
-                    projection: None,
+                    projection: [],
                 } => {
                     self.next = None;
                     return Some(cursor);
                 }
                 PlaceRef {
                     base: _,
-                    projection: Some(proj),
-                } => proj,
-            };
+                    projection: [proj_base @ .., elem],
+                } => {
+                    match elem {
+                        ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
+                            // FIXME: add union handling
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+                        ProjectionElem::Downcast(..) |
+                        ProjectionElem::Subslice { .. } |
+                        ProjectionElem::ConstantIndex { .. } |
+                        ProjectionElem::Index(_) => {
+                            cursor = PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            };
+                            continue 'cursor;
+                        }
+                        ProjectionElem::Deref => {
+                            // (handled below)
+                        }
+                    }
 
-            match proj.elem {
-                ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
-                    // FIXME: add union handling
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-                ProjectionElem::Downcast(..) |
-                ProjectionElem::Subslice { .. } |
-                ProjectionElem::ConstantIndex { .. } |
-                ProjectionElem::Index(_) => {
-                    cursor = PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    };
-                    continue 'cursor;
-                }
-                ProjectionElem::Deref => {
-                    // (handled below)
-                }
-            }
+                    assert_eq!(*elem, ProjectionElem::Deref);
 
-            assert_eq!(proj.elem, ProjectionElem::Deref);
+                    match self.kind {
+                        PrefixSet::Shallow => {
+                            // Shallow prefixes are found by stripping away
+                            // fields, but stop at *any* dereference.
+                            // So we can just stop the traversal now.
+                            self.next = None;
+                            return Some(cursor);
+                        }
+                        PrefixSet::All => {
+                            // All prefixes: just blindly enqueue the base
+                            // of the projection.
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+                        PrefixSet::Supporting => {
+                            // Fall through!
+                        }
+                    }
 
-            match self.kind {
-                PrefixSet::Shallow => {
-                    // shallow prefixes are found by stripping away
-                    // fields, but stop at *any* dereference.
-                    // So we can just stop the traversal now.
-                    self.next = None;
-                    return Some(cursor);
-                }
-                PrefixSet::All => {
-                    // all prefixes: just blindly enqueue the base
-                    // of the projection.
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-                PrefixSet::Supporting => {
-                    // fall through!
-                }
-            }
+                    assert_eq!(self.kind, PrefixSet::Supporting);
+                    // Supporting prefixes: strip away fields and
+                    // derefs, except we stop at the deref of a shared
+                    // reference.
 
-            assert_eq!(self.kind, PrefixSet::Supporting);
-            // supporting prefixes: strip away fields and
-            // derefs, except we stop at the deref of a shared
-            // reference.
+                    let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty;
+                    match ty.sty {
+                        ty::RawPtr(_) |
+                        ty::Ref(
+                            _, /*rgn*/
+                            _, /*ty*/
+                            hir::MutImmutable
+                            ) => {
+                            // don't continue traversing over derefs of raw pointers or shared
+                            // borrows.
+                            self.next = None;
+                            return Some(cursor);
+                        }
 
-            let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty;
-            match ty.sty {
-                ty::RawPtr(_) |
-                ty::Ref(
-                    _, /*rgn*/
-                    _, /*ty*/
-                    hir::MutImmutable
-                    ) => {
-                    // don't continue traversing over derefs of raw pointers or shared borrows.
-                    self.next = None;
-                    return Some(cursor);
+                        ty::Ref(
+                            _, /*rgn*/
+                            _, /*ty*/
+                            hir::MutMutable,
+                            ) => {
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+
+                        ty::Adt(..) if ty.is_box() => {
+                            self.next = Some(PlaceRef {
+                                base: cursor.base,
+                                projection: proj_base,
+                            });
+                            return Some(cursor);
+                        }
+
+                        _ => panic!("unknown type fed to Projection Deref."),
+                    }
                 }
-
-                ty::Ref(
-                    _, /*rgn*/
-                    _, /*ty*/
-                    hir::MutMutable,
-                    ) => {
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-
-                ty::Adt(..) if ty.is_box() => {
-                    self.next = Some(PlaceRef {
-                        base: cursor.base,
-                        projection: &proj.base,
-                    });
-                    return Some(cursor);
-                }
-
-                _ => panic!("unknown type fed to Projection Deref."),
             }
         }
     }
diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs
index 2587d14..695080d 100644
--- a/src/librustc_mir/borrow_check/used_muts.rs
+++ b/src/librustc_mir/borrow_check/used_muts.rs
@@ -89,7 +89,7 @@
         _location: Location,
     ) {
         match &statement.kind {
-            StatementKind::Assign(into, _) => {
+            StatementKind::Assign(box(into, _)) => {
                 if let PlaceBase::Local(local) = into.base {
                     debug!(
                         "visit_statement: statement={:?} local={:?} \
@@ -120,7 +120,7 @@
                 );
                 if let Place {
                     base: PlaceBase::Local(user_local),
-                    projection: None,
+                    projection: box [],
                 } = path.place {
                     self.mbcx.used_mut.insert(user_local);
                 }
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 778d1e7..3ed6b4f 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -37,7 +37,7 @@
                        rvalue: Rvalue<'tcx>) {
         self.push(block, Statement {
             source_info,
-            kind: StatementKind::Assign(place.clone(), box rvalue)
+            kind: StatementKind::Assign(box(place.clone(), rvalue))
         });
     }
 
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 98cf4bb..09b33c6 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -129,7 +129,7 @@
                     kind: StaticKind::Static,
                     def_id: id,
                 })),
-                projection: None,
+                projection: box [],
             }),
 
             ExprKind::PlaceTypeAscription { source, user_ty } => {
@@ -147,9 +147,11 @@
                         Statement {
                             source_info,
                             kind: StatementKind::AscribeUserType(
-                                place.clone(),
+                                box(
+                                    place.clone(),
+                                    UserTypeProjection { base: annotation_index, projs: vec![], }
+                                ),
                                 Variance::Invariant,
-                                box UserTypeProjection { base: annotation_index, projs: vec![], },
                             ),
                         },
                     );
@@ -174,9 +176,11 @@
                         Statement {
                             source_info,
                             kind: StatementKind::AscribeUserType(
-                                Place::from(temp.clone()),
+                                box(
+                                    Place::from(temp.clone()),
+                                    UserTypeProjection { base: annotation_index, projs: vec![], },
+                                ),
                                 Variance::Invariant,
-                                box UserTypeProjection { base: annotation_index, projs: vec![], },
                             ),
                         },
                     );
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 1a186fa..7dfe98c 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -500,14 +500,11 @@
         let mutability = match arg_place {
             Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             } => this.local_decls[local].mutability,
             Place {
                 base: PlaceBase::Local(local),
-                projection: Some(box Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                })
+                projection: box [ProjectionElem::Deref],
             } => {
                 debug_assert!(
                     this.local_decls[local].is_ref_for_guard(),
@@ -517,24 +514,19 @@
             }
             Place {
                 ref base,
-                projection: Some(box Projection {
-                    base: ref base_proj,
-                    elem: ProjectionElem::Field(upvar_index, _),
-                }),
+                projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             }
             | Place {
                 ref base,
-                projection: Some(box Projection {
-                    base: Some(box Projection {
-                        base: ref base_proj,
-                        elem: ProjectionElem::Field(upvar_index, _),
-                    }),
-                    elem: ProjectionElem::Deref,
-                }),
+                projection: box [
+                    ref proj_base @ ..,
+                    ProjectionElem::Field(upvar_index, _),
+                    ProjectionElem::Deref
+                ],
             } => {
                 let place = PlaceRef {
                     base,
-                    projection: base_proj,
+                    projection: proj_base,
                 };
 
                 // Not projected from the implicit `self` in a closure.
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 889861b..45f4a16 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -301,7 +301,7 @@
                 // Create a "fake" temporary variable so that we check that the
                 // value is Sized. Usually, this is caught in type checking, but
                 // in the case of box expr there is no such check.
-                if destination.projection.is_some() {
+                if !destination.projection.is_empty() {
                     this.local_decls
                         .push(LocalDecl::new_temp(expr.ty, expr.span));
                 }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 94323b1..2b0237c 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -135,7 +135,7 @@
             source_info,
             kind: StatementKind::FakeRead(
                 FakeReadCause::ForMatchedPlace,
-                scrutinee_place.clone(),
+                box(scrutinee_place.clone()),
             ),
         });
 
@@ -320,7 +320,7 @@
                     block,
                     Statement {
                         source_info,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, place),
+                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)),
                     },
                 );
 
@@ -362,12 +362,12 @@
                     block,
                     Statement {
                         source_info: pattern_source_info,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()),
+                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())),
                     },
                 );
 
                 let ty_source_info = self.source_info(user_ty_span);
-                let user_ty = box pat_ascription_ty.user_ty(
+                let user_ty = pat_ascription_ty.user_ty(
                     &mut self.canonical_user_type_annotations,
                     place.ty(&self.local_decls, self.hir.tcx()).ty,
                     ty_source_info.span,
@@ -377,7 +377,10 @@
                     Statement {
                         source_info: ty_source_info,
                         kind: StatementKind::AscribeUserType(
-                            place,
+                            box(
+                                place,
+                                user_ty,
+                            ),
                             // We always use invariant as the variance here. This is because the
                             // variance field from the ascription refers to the variance to use
                             // when applying the type to the value being matched, but this
@@ -393,7 +396,6 @@
                             // contrast, is intended to be used to relate `T` to the type of
                             // `<expr>`.
                             ty::Variance::Invariant,
-                            user_ty,
                         ),
                     },
                 );
@@ -942,16 +944,15 @@
             for Binding { source, .. }
                 in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
             {
-                let mut cursor = &source.projection;
-                while let Some(box Projection { base, elem }) = cursor {
-                    cursor = base;
-                    if let ProjectionElem::Deref = elem {
-                        fake_borrows.insert(Place {
-                            base: source.base.clone(),
-                            projection: cursor.clone(),
-                        });
-                        break;
-                    }
+                if let Some(i) =
+                    source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref)
+                {
+                    let proj_base = &source.projection[..i];
+
+                    fake_borrows.insert(Place {
+                        base: source.base.clone(),
+                        projection: proj_base.to_vec().into_boxed_slice(),
+                    });
                 }
             }
         }
@@ -1295,18 +1296,19 @@
         // Insert a Shallow borrow of the prefixes of any fake borrows.
         for place in fake_borrows
         {
-            let mut prefix_cursor = &place.projection;
-            while let Some(box Projection { base, elem }) = prefix_cursor {
+            let mut cursor = &*place.projection;
+            while let [proj_base @ .., elem] = cursor {
+                cursor = proj_base;
+
                 if let ProjectionElem::Deref = elem {
                     // Insert a shallow borrow after a deref. For other
                     // projections the borrow of prefix_cursor will
                     // conflict with any mutation of base.
                     all_fake_borrows.push(PlaceRef {
                         base: &place.base,
-                        projection: base,
+                        projection: proj_base,
                     });
                 }
-                prefix_cursor = base;
             }
 
             all_fake_borrows.push(place.as_ref());
@@ -1345,13 +1347,9 @@
     /// any, and then branches to the arm. Returns the block for the case where
     /// the guard fails.
     ///
-    /// Note: we check earlier that if there is a guard, there cannot be move
-    /// bindings (unless feature(bind_by_move_pattern_guards) is used). This
-    /// isn't really important for the self-consistency of this fn, but the
-    /// reason for it should be clear: after we've done the assignments, if
-    /// there were move bindings, further tests would be a use-after-move.
-    /// bind_by_move_pattern_guards avoids this by only moving the binding once
-    /// the guard has evaluated to true (see below).
+    /// Note: we do not check earlier that if there is a guard,
+    /// there cannot be move bindings. We avoid a use-after-move by only
+    /// moving the binding once the guard has evaluated to true (see below).
     fn bind_and_guard_matched_candidate<'pat>(
         &mut self,
         candidate: Candidate<'pat, 'tcx>,
@@ -1493,7 +1491,7 @@
                     BorrowKind::Shallow,
                     Place {
                         base: place.base.clone(),
-                        projection: place.projection.clone(),
+                        projection: place.projection.to_vec().into_boxed_slice(),
                     },
                 );
                 self.cfg.push_assign(
@@ -1524,7 +1522,7 @@
                     source_info: guard_end,
                     kind: StatementKind::FakeRead(
                         FakeReadCause::ForMatchGuard,
-                        Place::from(temp),
+                        box(Place::from(temp)),
                     ),
                 });
             }
@@ -1574,7 +1572,7 @@
                     post_guard_block,
                     Statement {
                         source_info: guard_end,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place),
+                        kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)),
                     },
                 );
             }
@@ -1607,7 +1605,7 @@
                 ascription.user_ty,
             );
 
-            let user_ty = box ascription.user_ty.clone().user_ty(
+            let user_ty = ascription.user_ty.clone().user_ty(
                 &mut self.canonical_user_type_annotations,
                 ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
                 source_info.span
@@ -1617,9 +1615,11 @@
                 Statement {
                     source_info,
                     kind: StatementKind::AscribeUserType(
-                        ascription.source.clone(),
+                        box(
+                            ascription.source.clone(),
+                            user_ty,
+                        ),
                         ascription.variance,
-                        user_ty,
                     ),
                 },
             );
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 7ab0bf7..647d751 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -609,7 +609,7 @@
         unpack!(block = builder.in_breakable_scope(
             None,
             START_BLOCK,
-            Place::RETURN_PLACE,
+            Place::return_place(),
             |builder| {
                 builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
                     builder.args_and_body(block, &arguments, arg_scope, &body.value)
@@ -670,7 +670,7 @@
     let mut block = START_BLOCK;
     let ast_expr = &tcx.hir().body(body_id).value;
     let expr = builder.hir.mirror(ast_expr);
-    unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr));
+    unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
 
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@@ -871,7 +871,7 @@
         }
 
         let body = self.hir.mirror(ast_body);
-        self.into(&Place::RETURN_PLACE, block, body)
+        self.into(&Place::return_place(), block, body)
     }
 
     fn set_correct_source_scope_for_arg(
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index a04c041..ee6d42d 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -314,7 +314,7 @@
         match target {
             BreakableTarget::Return => {
                 let scope = &self.breakable_scopes[0];
-                if scope.break_destination != Place::RETURN_PLACE {
+                if scope.break_destination != Place::return_place() {
                     span_bug!(span, "`return` in item with no return scope");
                 }
                 (scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
@@ -853,11 +853,11 @@
             _ if self.local_scope().is_none() => (),
             Operand::Copy(Place {
                 base: PlaceBase::Local(cond_temp),
-                projection: None,
+                projection: box [],
             })
             | Operand::Move(Place {
                 base: PlaceBase::Local(cond_temp),
-                projection: None,
+                projection: box [],
             }) => {
                 // Manually drop the condition on both branches.
                 let top_scope = self.scopes.scopes.last_mut().unwrap();
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index db67902..4351598 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -15,6 +15,7 @@
 use rustc::ty::layout::{self, LayoutOf, VariantIdx};
 use rustc::traits::Reveal;
 use rustc_data_structures::fx::FxHashMap;
+use crate::interpret::eval_nullary_intrinsic;
 
 use syntax::source_map::{Span, DUMMY_SP};
 
@@ -134,9 +135,8 @@
     ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
     cid: GlobalId<'tcx>,
     body: &'mir mir::Body<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
 ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
-    debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
+    debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env);
     let tcx = ecx.tcx.tcx;
     let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?;
     assert!(!layout.is_unsized());
@@ -162,7 +162,6 @@
         ecx,
         cid.instance.def_id(),
         ret,
-        param_env,
     )?;
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
@@ -383,7 +382,7 @@
             return Ok(());
         }
         // An intrinsic that we do not support
-        let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..];
+        let intrinsic_name = ecx.tcx.item_name(instance.def_id());
         Err(
             ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()
         )
@@ -589,7 +588,7 @@
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
-    // see comment in const_eval_provider for what we're doing here
+    // see comment in const_eval_raw_provider for what we're doing here
     if key.param_env.reveal == Reveal::All {
         let mut key = key.clone();
         key.param_env.reveal = Reveal::UserFacing;
@@ -604,6 +603,23 @@
             other => return other,
         }
     }
+
+    // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
+    // Catch such calls and evaluate them instead of trying to load a constant's MIR.
+    if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
+        let ty = key.value.instance.ty(tcx);
+        let substs = match ty.sty {
+            ty::FnDef(_, substs) => substs,
+            _ => bug!("intrinsic with type {:?}", ty),
+        };
+        return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs)
+            .map_err(|error| {
+                let span = tcx.def_span(def_id);
+                let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span };
+                error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
+            })
+    }
+
     tcx.const_eval_raw(key).and_then(|val| {
         validate_and_turn_into_const(tcx, val, key)
     })
@@ -658,7 +674,7 @@
 
     let res = ecx.load_mir(cid.instance.def, cid.promoted);
     res.and_then(
-        |body| eval_body_using_ecx(&mut ecx, cid, body, key.param_env)
+        |body| eval_body_using_ecx(&mut ecx, cid, body)
     ).and_then(|place| {
         Ok(RawConst {
             alloc_id: place.ptr.assert_ptr().alloc_id,
diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs
index c071b31..444cc00 100644
--- a/src/librustc_mir/dataflow/drop_flag_effects.rs
+++ b/src/librustc_mir/dataflow/drop_flag_effects.rs
@@ -10,19 +10,17 @@
                                         path: MovePathIndex,
                                         mut cond: F)
                                         -> Option<MovePathIndex>
-    where F: FnMut(&mir::Projection<'tcx>) -> bool
+    where F: FnMut(&mir::PlaceElem<'tcx>) -> bool
 {
     let mut next_child = move_data.move_paths[path].first_child;
     while let Some(child_index) = next_child {
-        match move_data.move_paths[child_index].place.projection {
-            Some(ref proj) => {
-                if cond(proj) {
-                    return Some(child_index)
-                }
+        let move_path_children = &move_data.move_paths[child_index];
+        if let Some(elem) = move_path_children.place.projection.last() {
+            if cond(elem) {
+                return Some(child_index)
             }
-            _ => {}
         }
-        next_child = move_data.move_paths[child_index].next_sibling;
+        next_child = move_path_children.next_sibling;
     }
 
     None
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 2ea6c4a..a86fcb3 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -208,7 +208,7 @@
             // If the borrowed place is a local with no projections, all other borrows of this
             // local must conflict. This is purely an optimization so we don't have to call
             // `places_conflict` for every borrow.
-            if place.projection.is_none() {
+            if place.projection.is_empty() {
                 trans.kill_all(other_borrows_of_local);
                 return;
             }
@@ -268,8 +268,8 @@
 
         debug!("Borrows::statement_effect: stmt={:?}", stmt);
         match stmt.kind {
-            mir::StatementKind::Assign(ref lhs, ref rhs) => {
-                if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
+            mir::StatementKind::Assign(box(ref lhs, ref rhs)) => {
+                if let mir::Rvalue::Ref(_, _, ref place) = *rhs {
                     if place.ignore_borrow(
                         self.tcx,
                         self.body,
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
index 0e01701..0f66b13 100644
--- a/src/librustc_mir/dataflow/impls/storage_liveness.rs
+++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs
@@ -119,8 +119,8 @@
         match stmt.kind {
             StatementKind::StorageLive(l) => sets.gen(l),
             StatementKind::StorageDead(l) => sets.kill(l),
-            StatementKind::Assign(ref place, _)
-            | StatementKind::SetDiscriminant { ref place, .. } => {
+            StatementKind::Assign(box(ref place, _))
+            | StatementKind::SetDiscriminant { box ref place, .. } => {
                 if let PlaceBase::Local(local) = place.base {
                     sets.gen(local);
                 }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 81451c2..698c501 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -94,72 +94,74 @@
     /// Maybe we should have separate "borrowck" and "moveck" modes.
     fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
         debug!("lookup({:?})", place);
-        place.iterate(|place_base, place_projection| {
-            let mut base = match place_base {
-                PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local],
-                PlaceBase::Static(..) => {
-                    return Err(MoveError::cannot_move_out_of(self.loc, Static));
+        let mut base = match place.base {
+            PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
+            PlaceBase::Static(..) => {
+                return Err(MoveError::cannot_move_out_of(self.loc, Static));
+            }
+        };
+
+        for (i, elem) in place.projection.iter().enumerate() {
+            let proj_base = &place.projection[..i];
+            let body = self.builder.body;
+            let tcx = self.builder.tcx;
+            let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty;
+            match place_ty.sty {
+                ty::Ref(..) | ty::RawPtr(..) => {
+                    let proj = &place.projection[..i+1];
+                    return Err(MoveError::cannot_move_out_of(
+                        self.loc,
+                        BorrowedContent {
+                            target_place: Place {
+                                base: place.base.clone(),
+                                projection: proj.to_vec().into_boxed_slice(),
+                            },
+                        },
+                    ));
                 }
+                ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
+                    return Err(MoveError::cannot_move_out_of(
+                        self.loc,
+                        InteriorOfTypeWithDestructor { container_ty: place_ty },
+                    ));
+                }
+                // move out of union - always move the entire union
+                ty::Adt(adt, _) if adt.is_union() => {
+                    return Err(MoveError::UnionMove { path: base });
+                }
+                ty::Slice(_) => {
+                    return Err(MoveError::cannot_move_out_of(
+                        self.loc,
+                        InteriorOfSliceOrArray {
+                            ty: place_ty,
+                            is_index: match elem {
+                                ProjectionElem::Index(..) => true,
+                                _ => false,
+                            },
+                        },
+                    ));
+                }
+                ty::Array(..) => match elem {
+                    ProjectionElem::Index(..) => {
+                        return Err(MoveError::cannot_move_out_of(
+                            self.loc,
+                            InteriorOfSliceOrArray { ty: place_ty, is_index: true },
+                        ));
+                    }
+                    _ => {
+                        // FIXME: still badly broken
+                    }
+                },
+                _ => {}
             };
 
-            for proj in place_projection {
-                let body = self.builder.body;
-                let tcx = self.builder.tcx;
-                let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
-                match place_ty.sty {
-                    ty::Ref(..) | ty::RawPtr(..) => {
-                        return Err(MoveError::cannot_move_out_of(
-                            self.loc,
-                            BorrowedContent {
-                                target_place: Place {
-                                    base: place_base.clone(),
-                                    projection: Some(Box::new(proj.clone())),
-                                },
-                            },
-                        ));
-                    }
-                    ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
-                        return Err(MoveError::cannot_move_out_of(
-                            self.loc,
-                            InteriorOfTypeWithDestructor { container_ty: place_ty },
-                        ));
-                    }
-                    // move out of union - always move the entire union
-                    ty::Adt(adt, _) if adt.is_union() => {
-                        return Err(MoveError::UnionMove { path: base });
-                    }
-                    ty::Slice(_) => {
-                        return Err(MoveError::cannot_move_out_of(
-                            self.loc,
-                            InteriorOfSliceOrArray {
-                                ty: place_ty,
-                                is_index: match proj.elem {
-                                    ProjectionElem::Index(..) => true,
-                                    _ => false,
-                                },
-                            },
-                        ));
-                    }
-                    ty::Array(..) => match proj.elem {
-                        ProjectionElem::Index(..) => {
-                            return Err(MoveError::cannot_move_out_of(
-                                self.loc,
-                                InteriorOfSliceOrArray { ty: place_ty, is_index: true },
-                            ));
-                        }
-                        _ => {
-                            // FIXME: still badly broken
-                        }
-                    },
-                    _ => {}
-                };
-
-                base = match self
-                    .builder
-                    .data
-                    .rev_lookup
-                    .projections
-                    .entry((base, proj.elem.lift()))
+            let proj = &place.projection[..i+1];
+            base = match self
+                .builder
+                .data
+                .rev_lookup
+                .projections
+                .entry((base, elem.lift()))
                 {
                     Entry::Occupied(ent) => *ent.get(),
                     Entry::Vacant(ent) => {
@@ -169,18 +171,17 @@
                             &mut self.builder.data.init_path_map,
                             Some(base),
                             Place {
-                                base: place_base.clone(),
-                                projection: Some(Box::new(proj.clone())),
+                                base: place.base.clone(),
+                                projection: proj.to_vec().into_boxed_slice(),
                             },
                         );
                         ent.insert(path);
                         path
                     }
                 };
-            }
+        }
 
-            Ok(base)
-        })
+        Ok(base)
     }
 
     fn create_move_path(&mut self, place: &Place<'tcx>) {
@@ -267,7 +268,7 @@
 impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
         match stmt.kind {
-            StatementKind::Assign(ref place, ref rval) => {
+            StatementKind::Assign(box(ref place, ref rval)) => {
                 self.create_move_path(place);
                 if let RvalueInitializationState::Shallow = rval.initialization_state() {
                     // Box starts out uninitialized - need to create a separate
@@ -355,7 +356,7 @@
             | TerminatorKind::Unreachable => {}
 
             TerminatorKind::Return => {
-                self.gather_move(&Place::RETURN_PLACE);
+                self.gather_move(&Place::return_place());
             }
 
             TerminatorKind::Assert { ref cond, .. } => {
@@ -435,9 +436,7 @@
 
         // Check if we are assigning into a field of a union, if so, lookup the place
         // of the union so it is marked as initialized again.
-        if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) =
-            place.projection
-        {
+        if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
             if let ty::Adt(def, _) =
                 Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty
             {
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index 5028e96..156c19c 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -245,23 +245,21 @@
     // alternative will *not* create a MovePath on the fly for an
     // unknown place, but will rather return the nearest available
     // parent.
-    pub fn find(&self, place_ref: PlaceRef<'_, '_>) -> LookupResult {
-        place_ref.iterate(|place_base, place_projection| {
-            let mut result = match place_base {
-                PlaceBase::Local(local) => self.locals[*local],
-                PlaceBase::Static(..) => return LookupResult::Parent(None),
-            };
+    pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
+        let mut result = match place.base {
+            PlaceBase::Local(local) => self.locals[*local],
+            PlaceBase::Static(..) => return LookupResult::Parent(None),
+        };
 
-            for proj in place_projection {
-                if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
-                    result = subpath;
-                } else {
-                    return LookupResult::Parent(Some(result));
-                }
+        for elem in place.projection.iter() {
+            if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
+                result = subpath;
+            } else {
+                return LookupResult::Parent(Some(result));
             }
+        }
 
-            LookupResult::Exact(result)
-        })
+        LookupResult::Exact(result)
     }
 
     pub fn find_local(&self, local: Local) -> MovePathIndex {
@@ -329,7 +327,7 @@
     pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
         loop {
             let path = &self.move_paths[mpi];
-            if let Place { base: PlaceBase::Local(l), projection: None } = path.place {
+            if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
                 return Some(l);
             }
             if let Some(parent) = path.parent {
diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs
index d80449a..ba299e9 100644
--- a/src/librustc_mir/error_codes.rs
+++ b/src/librustc_mir/error_codes.rs
@@ -157,81 +157,6 @@
 See also the error E0303.
 "##,
 
-E0008: r##"
-Names bound in match arms retain their type in pattern guards. As such, if a
-name is bound by move in a pattern, it should also be moved to wherever it is
-referenced in the pattern guard code. Doing so however would prevent the name
-from being available in the body of the match arm. Consider the following:
-
-```compile_fail,E0008
-match Some("hi".to_string()) {
-    Some(s) if s.len() == 0 => {}, // use s.
-    _ => {},
-}
-```
-
-The variable `s` has type `String`, and its use in the guard is as a variable of
-type `String`. The guard code effectively executes in a separate scope to the
-body of the arm, so the value would be moved into this anonymous scope and
-therefore becomes unavailable in the body of the arm.
-
-The problem above can be solved by using the `ref` keyword.
-
-```
-match Some("hi".to_string()) {
-    Some(ref s) if s.len() == 0 => {},
-    _ => {},
-}
-```
-
-Though this example seems innocuous and easy to solve, the problem becomes clear
-when it encounters functions which consume the value:
-
-```compile_fail,E0008
-struct A{}
-
-impl A {
-    fn consume(self) -> usize {
-        0
-    }
-}
-
-fn main() {
-    let a = Some(A{});
-    match a {
-        Some(y) if y.consume() > 0 => {}
-        _ => {}
-    }
-}
-```
-
-In this situation, even the `ref` keyword cannot solve it, since borrowed
-content cannot be moved. This problem cannot be solved generally. If the value
-can be cloned, here is a not-so-specific solution:
-
-```
-#[derive(Clone)]
-struct A{}
-
-impl A {
-    fn consume(self) -> usize {
-        0
-    }
-}
-
-fn main() {
-    let a = Some(A{});
-    match a{
-        Some(ref y) if y.clone().consume() > 0 => {}
-        _ => {}
-    }
-}
-```
-
-If the value will be consumed in the pattern guard, using its clone will not
-move its ownership, so the code works.
-"##,
-
 E0009: r##"
 In a pattern, all values that don't implement the `Copy` trait have to be bound
 the same way. The goal here is to avoid binding simultaneously by-move and
@@ -475,13 +400,15 @@
 "##,
 
 E0301: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 Mutable borrows are not allowed in pattern guards, because matching cannot have
 side effects. Side effects could alter the matched object or the environment
 on which the match depends in such a way, that the match would not be
 exhaustive. For instance, the following would not match any arm if mutable
 borrows were allowed:
 
-```compile_fail,E0301
+```compile_fail,E0596
 match Some(()) {
     None => { },
     option if option.take().is_none() => {
@@ -493,13 +420,15 @@
 "##,
 
 E0302: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 Assignments are not allowed in pattern guards, because matching cannot have
 side effects. Side effects could alter the matched object or the environment
 on which the match depends in such a way, that the match would not be
 exhaustive. For instance, the following would not match any arm if assignments
 were allowed:
 
-```compile_fail,E0302
+```compile_fail,E0594
 match Some(()) {
     None => { },
     option if { option = None; false } => { },
@@ -1717,7 +1646,14 @@
 "##,
 
 E0507: r##"
-You tried to move out of a value which was borrowed. Erroneous code example:
+You tried to move out of a value which was borrowed.
+
+This can also happen when using a type implementing `Fn` or `FnMut`, as neither
+allows moving out of them (they usually represent closures which can be called
+more than once). Much of the text following applies equally well to non-`FnOnce`
+closure bodies.
+
+Erroneous code example:
 
 ```compile_fail,E0507
 use std::cell::RefCell;
@@ -1989,7 +1925,6 @@
 could cause the match to be non-exhaustive:
 
 ```compile_fail,E0510
-#![feature(bind_by_move_pattern_guards)]
 let mut x = Some(0);
 match x {
     None => (),
@@ -2451,6 +2386,7 @@
 
 ;
 
+//  E0008, // cannot bind by-move into a pattern guard
 //  E0298, // cannot compare constants
 //  E0299, // mismatched types between arms
 //  E0471, // constant evaluation error (in pattern)
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 222750e..a6d955f 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -517,9 +517,9 @@
 pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
 
 impl<'tcx> Witness<'tcx> {
-    pub fn single_pattern(&self) -> &Pattern<'tcx> {
+    pub fn single_pattern(self) -> Pattern<'tcx> {
         assert_eq!(self.0.len(), 1);
-        &self.0[0]
+        self.0.into_iter().next().unwrap()
     }
 
     fn push_wild_constructor<'a>(
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 5352888..161c58a 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -5,11 +5,6 @@
 use super::{Pattern, PatternContext, PatternError, PatternKind};
 
 use rustc::middle::borrowck::SignalledError;
-use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
-use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
-use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::mem_categorization::cmt_;
-use rustc::middle::region;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::{InternalSubsts, SubstsRef};
@@ -36,9 +31,7 @@
 
     let mut visitor = MatchVisitor {
         tcx,
-        body_owner: def_id,
         tables: tcx.body_tables(body_id),
-        region_scope_tree: &tcx.region_scope_tree(def_id),
         param_env: tcx.param_env(def_id),
         identity_substs: InternalSubsts::identity_for_item(tcx, def_id),
         signalled_error: SignalledError::NoErrorsSeen,
@@ -53,15 +46,13 @@
 
 struct MatchVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    body_owner: DefId,
     tables: &'a ty::TypeckTables<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     identity_substs: SubstsRef<'tcx>,
-    region_scope_tree: &'a region::ScopeTree,
     signalled_error: SignalledError,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
@@ -98,8 +89,7 @@
     }
 }
 
-
-impl<'a, 'tcx> PatternContext<'a, 'tcx> {
+impl PatternContext<'_, '_> {
     fn report_inlining_errors(&self, pat_span: Span) {
         for error in &self.errors {
             match *error {
@@ -131,7 +121,7 @@
     }
 }
 
-impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
+impl<'tcx> MatchVisitor<'_, 'tcx> {
     fn check_patterns(&mut self, has_guard: bool, pats: &[P<Pat>]) {
         check_legality_of_move_bindings(self, has_guard, pats);
         for pat in pats {
@@ -151,11 +141,8 @@
 
             // Second, if there is a guard on each arm, make sure it isn't
             // assigning or borrowing anything mutably.
-            if let Some(ref guard) = arm.guard {
+            if arm.guard.is_some() {
                 self.signalled_error = SignalledError::SawSomeError;
-                if !self.tcx.features().bind_by_move_pattern_guards {
-                    check_for_mutation_in_guard(self, &guard);
-                }
             }
 
             // Third, perform some lints.
@@ -277,37 +264,26 @@
                 expand_pattern(cx, pattern)
             ]].into_iter().collect();
 
-            let wild_pattern = Pattern {
-                ty: pattern_ty,
-                span: DUMMY_SP,
-                kind: box PatternKind::Wild,
-            };
-            let witness = match is_useful(cx, &pats, &[&wild_pattern], ConstructWitness) {
-                UsefulWithWitness(witness) => witness,
-                NotUseful => return,
-                Useful => bug!()
+            let witnesses = match check_not_useful(cx, pattern_ty, &pats) {
+                Ok(_) => return,
+                Err(err) => err,
             };
 
-            let pattern_string = witness[0].single_pattern().to_string();
+            let joined_patterns = joined_uncovered_patterns(&witnesses);
             let mut err = struct_span_err!(
                 self.tcx.sess, pat.span, E0005,
-                "refutable pattern in {}: `{}` not covered",
-                origin, pattern_string
+                "refutable pattern in {}: {} not covered",
+                origin, joined_patterns
             );
-            let label_msg = match pat.node {
-                PatKind::Path(hir::QPath::Resolved(None, ref path))
-                        if path.segments.len() == 1 && path.segments[0].args.is_none() => {
+            err.span_label(pat.span, match &pat.node {
+                PatKind::Path(hir::QPath::Resolved(None, path))
+                    if path.segments.len() == 1 && path.segments[0].args.is_none() => {
                     format!("interpreted as {} {} pattern, not new variable",
                             path.res.article(), path.res.descr())
                 }
-                _ => format!("pattern `{}` not covered", pattern_string),
-            };
-            err.span_label(pat.span, label_msg);
-            if let ty::Adt(def, _) = pattern_ty.sty {
-                if let Some(sp) = self.tcx.hir().span_if_local(def.did){
-                    err.span_label(sp, format!("`{}` defined here", pattern_ty));
-                }
-            }
+                _ => pattern_not_convered_label(&witnesses, &joined_patterns),
+            });
+            adt_defined_here(cx, &mut err, pattern_ty, &witnesses);
             err.emit();
         });
     }
@@ -362,9 +338,9 @@
 }
 
 // Check for unreachable patterns
-fn check_arms<'a, 'tcx>(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)],
+fn check_arms<'tcx>(
+    cx: &mut MatchCheckCtxt<'_, 'tcx>,
+    arms: &[(Vec<(&Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)],
     source: hir::MatchSource,
 ) {
     let mut seen = Matrix::empty();
@@ -445,104 +421,124 @@
     }
 }
 
-fn check_exhaustive<'p, 'a, 'tcx>(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    scrut_ty: Ty<'tcx>,
-    sp: Span,
-    matrix: &Matrix<'p, 'tcx>,
-) {
-    let wild_pattern = Pattern {
-        ty: scrut_ty,
-        span: DUMMY_SP,
-        kind: box PatternKind::Wild,
-    };
+fn check_not_useful(
+    cx: &mut MatchCheckCtxt<'_, 'tcx>,
+    ty: Ty<'tcx>,
+    matrix: &Matrix<'_, 'tcx>,
+) -> Result<(), Vec<Pattern<'tcx>>> {
+    let wild_pattern = Pattern { ty, span: DUMMY_SP, kind: box PatternKind::Wild };
     match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
-        UsefulWithWitness(pats) => {
-            let witnesses = if pats.is_empty() {
-                vec![&wild_pattern]
-            } else {
-                pats.iter().map(|w| w.single_pattern()).collect()
-            };
-
-            const LIMIT: usize = 3;
-            let joined_patterns = match witnesses.len() {
-                0 => bug!(),
-                1 => format!("`{}`", witnesses[0]),
-                2..=LIMIT => {
-                    let (tail, head) = witnesses.split_last().unwrap();
-                    let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
-                    format!("`{}` and `{}`", head.join("`, `"), tail)
-                }
-                _ => {
-                    let (head, tail) = witnesses.split_at(LIMIT);
-                    let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
-                    format!("`{}` and {} more", head.join("`, `"), tail.len())
-                }
-            };
-
-            let label_text = match witnesses.len() {
-                1 => format!("pattern {} not covered", joined_patterns),
-                _ => format!("patterns {} not covered", joined_patterns),
-            };
-            let mut err = create_e0004(cx.tcx.sess, sp, format!(
-                "non-exhaustive patterns: {} not covered",
-                joined_patterns,
-            ));
-            err.span_label(sp, label_text);
-            // point at the definition of non-covered enum variants
-            if let ty::Adt(def, _) = scrut_ty.sty {
-                if let Some(sp) = cx.tcx.hir().span_if_local(def.did){
-                    err.span_label(sp, format!("`{}` defined here", scrut_ty));
-                }
-            }
-            let patterns = witnesses.iter().map(|p| (**p).clone()).collect::<Vec<Pattern<'_>>>();
-            if patterns.len() < 4 {
-                for sp in maybe_point_at_variant(cx, scrut_ty, patterns.as_slice()) {
-                    err.span_label(sp, "not covered");
-                }
-            }
-            err.help("ensure that all possible cases are being handled, \
-                      possibly by adding wildcards or more match arms");
-            err.emit();
-        }
-        NotUseful => {
-            // This is good, wildcard pattern isn't reachable
-        }
-        _ => bug!()
+        NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
+        UsefulWithWitness(pats) => Err(if pats.is_empty() {
+            vec![wild_pattern]
+        } else {
+            pats.into_iter().map(|w| w.single_pattern()).collect()
+        }),
+        Useful => bug!(),
     }
 }
 
-fn maybe_point_at_variant(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    ty: Ty<'tcx>,
-    patterns: &[Pattern<'_>],
-) -> Vec<Span> {
+fn check_exhaustive<'tcx>(
+    cx: &mut MatchCheckCtxt<'_, 'tcx>,
+    scrut_ty: Ty<'tcx>,
+    sp: Span,
+    matrix: &Matrix<'_, 'tcx>,
+) {
+    let witnesses = match check_not_useful(cx, scrut_ty, matrix) {
+        Ok(_) => return,
+        Err(err) => err,
+    };
+
+    let joined_patterns = joined_uncovered_patterns(&witnesses);
+    let mut err = create_e0004(
+        cx.tcx.sess, sp,
+        format!("non-exhaustive patterns: {} not covered", joined_patterns),
+    );
+    err.span_label(sp, pattern_not_convered_label(&witnesses, &joined_patterns));
+    adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
+    err.help(
+        "ensure that all possible cases are being handled, \
+        possibly by adding wildcards or more match arms"
+    )
+    .emit();
+}
+
+fn joined_uncovered_patterns(witnesses: &[Pattern<'_>]) -> String {
+    const LIMIT: usize = 3;
+    match witnesses {
+        [] => bug!(),
+        [witness] => format!("`{}`", witness),
+        [head @ .., tail] if head.len() < LIMIT => {
+            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
+            format!("`{}` and `{}`", head.join("`, `"), tail)
+        }
+        _ => {
+            let (head, tail) = witnesses.split_at(LIMIT);
+            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
+            format!("`{}` and {} more", head.join("`, `"), tail.len())
+        }
+    }
+}
+
+fn pattern_not_convered_label(witnesses: &[Pattern<'_>], joined_patterns: &str) -> String {
+    format!("pattern{} {} not covered", rustc_errors::pluralise!(witnesses.len()), joined_patterns)
+}
+
+/// Point at the definition of non-covered `enum` variants.
+fn adt_defined_here(
+    cx: &MatchCheckCtxt<'_, '_>,
+    err: &mut DiagnosticBuilder<'_>,
+    ty: Ty<'_>,
+    witnesses: &[Pattern<'_>],
+) {
+    let ty = ty.peel_refs();
+    if let ty::Adt(def, _) = ty.sty {
+        if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
+            err.span_label(sp, format!("`{}` defined here", ty));
+        }
+
+        if witnesses.len() < 4 {
+            for sp in maybe_point_at_variant(ty, &witnesses) {
+                err.span_label(sp, "not covered");
+            }
+        }
+    }
+}
+
+fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[Pattern<'_>]) -> Vec<Span> {
     let mut covered = vec![];
     if let ty::Adt(def, _) = ty.sty {
         // Don't point at variants that have already been covered due to other patterns to avoid
-        // visual clutter
+        // visual clutter.
         for pattern in patterns {
-            let pk: &PatternKind<'_> = &pattern.kind;
-            if let PatternKind::Variant { adt_def, variant_index, subpatterns, .. } = pk {
-                if adt_def.did == def.did {
+            use PatternKind::{AscribeUserType, Deref, Variant, Or, Leaf};
+            match &*pattern.kind {
+                AscribeUserType { subpattern, .. } | Deref { subpattern } => {
+                    covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern)));
+                }
+                Variant { adt_def, variant_index, subpatterns, .. } if adt_def.did == def.did => {
                     let sp = def.variants[*variant_index].ident.span;
                     if covered.contains(&sp) {
                         continue;
                     }
                     covered.push(sp);
-                    let subpatterns = subpatterns.iter()
+
+                    let pats = subpatterns.iter()
                         .map(|field_pattern| field_pattern.pattern.clone())
-                        .collect::<Vec<_>>();
-                    covered.extend(
-                        maybe_point_at_variant(cx, ty, subpatterns.as_slice()),
-                    );
+                        .collect::<Box<[_]>>();
+                    covered.extend(maybe_point_at_variant(ty, &pats));
                 }
-            }
-            if let PatternKind::Leaf { subpatterns } = pk {
-                let subpatterns = subpatterns.iter()
-                    .map(|field_pattern| field_pattern.pattern.clone())
-                    .collect::<Vec<_>>();
-                covered.extend(maybe_point_at_variant(cx, ty, subpatterns.as_slice()));
+                Leaf { subpatterns } => {
+                    let pats = subpatterns.iter()
+                        .map(|field_pattern| field_pattern.pattern.clone())
+                        .collect::<Box<[_]>>();
+                    covered.extend(maybe_point_at_variant(ty, &pats));
+                }
+                Or { pats } => {
+                    let pats = pats.iter().cloned().collect::<Box<[_]>>();
+                    covered.extend(maybe_point_at_variant(ty, &pats));
+                }
+                _ => {}
             }
         }
     }
@@ -582,19 +578,10 @@
                              "cannot bind by-move with sub-bindings")
                 .span_label(p.span, "binds an already bound by-move value by moving it")
                 .emit();
-        } else if has_guard {
-            if !cx.tcx.features().bind_by_move_pattern_guards {
-                let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
-                                            "cannot bind by-move into a pattern guard");
-                err.span_label(p.span, "moves value into pattern guard");
-                if cx.tcx.sess.opts.unstable_features.is_nightly_build() {
-                    err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \
-                            crate attributes to enable");
-                }
-                err.emit();
+        } else if !has_guard {
+            if let Some(_by_ref_span) = by_ref_span {
+                span_vec.push(p.span);
             }
-        } else if let Some(_by_ref_span) = by_ref_span {
-            span_vec.push(p.span);
         }
     };
 
@@ -636,67 +623,6 @@
     }
 }
 
-/// Ensures that a pattern guard doesn't borrow by mutable reference or assign.
-//
-// FIXME: this should be done by borrowck.
-fn check_for_mutation_in_guard(cx: &MatchVisitor<'_, '_>, guard: &hir::Guard) {
-    let mut checker = MutationChecker {
-        cx,
-    };
-    match guard {
-        hir::Guard::If(expr) =>
-            ExprUseVisitor::new(&mut checker,
-                                cx.tcx,
-                                cx.body_owner,
-                                cx.param_env,
-                                cx.region_scope_tree,
-                                cx.tables,
-                                None).walk_expr(expr),
-    };
-}
-
-struct MutationChecker<'a, 'tcx> {
-    cx: &'a MatchVisitor<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
-    fn matched_pat(&mut self, _: &Pat, _: &cmt_<'_>, _: euv::MatchMode) {}
-    fn consume(&mut self, _: hir::HirId, _: Span, _: &cmt_<'_>, _: ConsumeMode) {}
-    fn consume_pat(&mut self, _: &Pat, _: &cmt_<'_>, _: ConsumeMode) {}
-    fn borrow(&mut self,
-              _: hir::HirId,
-              span: Span,
-              _: &cmt_<'_>,
-              _: ty::Region<'tcx>,
-              kind:ty:: BorrowKind,
-              _: LoanCause) {
-        match kind {
-            ty::MutBorrow => {
-                let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301,
-                          "cannot mutably borrow in a pattern guard");
-                err.span_label(span, "borrowed mutably in pattern guard");
-                if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() {
-                    err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \
-                              crate attributes to enable");
-                }
-                err.emit();
-            }
-            ty::ImmBorrow | ty::UniqueImmBorrow => {}
-        }
-    }
-    fn decl_without_init(&mut self, _: hir::HirId, _: Span) {}
-    fn mutate(&mut self, _: hir::HirId, span: Span, _: &cmt_<'_>, mode: MutateMode) {
-        match mode {
-            MutateMode::JustWrite | MutateMode::WriteAndRead => {
-                struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
-                    .span_label(span, "assignment in pattern guard")
-                    .emit();
-            }
-            MutateMode::Init => {}
-        }
-    }
-}
-
 /// Forbids bindings in `@` patterns. This is necessary for memory safety,
 /// because of the way rvalues are handled in the borrow check. (See issue
 /// #14587.)
@@ -709,7 +635,7 @@
     bindings_allowed: bool
 }
 
-impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
+impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
         NestedVisitorMap::None
     }
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 6caccfd..4aaa5e8 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -1229,7 +1229,13 @@
                 ty::RawPtr(..) => {
                     // `#[structural_match]` ignores substructure of
                     // `*const _`/`*mut _`, so skip super_visit_with
-
+                    //
+                    // (But still tell caller to continue search.)
+                    return false;
+                }
+                ty::FnDef(..) | ty::FnPtr(..) => {
+                    // types of formals and return in `fn(_) -> _` are also irrelevant
+                    //
                     // (But still tell caller to continue search.)
                     return false;
                 }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 054b65f..78996ed 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -14,7 +14,6 @@
 use rustc::ty::query::TyCtxtAt;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::mir::interpret::{
-    ErrorHandled,
     GlobalId, Scalar, Pointer, FrameInfo, AllocId,
     InterpResult, truncate, sign_extend,
 };
@@ -672,14 +671,7 @@
         // Our result will later be validated anyway, and there seems no good reason
         // to have to fail early here.  This is also more consistent with
         // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
-        let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
-            match err {
-                ErrorHandled::Reported =>
-                    err_inval!(ReferencedConstant),
-                ErrorHandled::TooGeneric =>
-                    err_inval!(TooGeneric),
-            }
-        })?;
+        let val = self.tcx.const_eval_raw(param_env.and(gid))?;
         self.raw_const_to_mplace(val)
     }
 
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index 4cbbc0f..95647ce 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -3,7 +3,7 @@
 //! After a const evaluation has computed a value, before we destroy the const evaluator's session
 //! memory, we need to extract all memory allocations to the global memory pool so they stay around.
 
-use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
+use rustc::ty::{Ty, self};
 use rustc::mir::interpret::{InterpResult, ErrorHandled};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
@@ -11,32 +11,29 @@
 use rustc_data_structures::fx::FxHashSet;
 
 use syntax::ast::Mutability;
-use syntax_pos::Span;
 
 use super::{
-    ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, Scalar,
+    ValueVisitor, MemoryKind, AllocId, MPlaceTy, Scalar,
 };
 use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};
 
 struct InternVisitor<'rt, 'mir, 'tcx> {
-    /// previously encountered safe references
-    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
+    /// The ectx from which we intern.
     ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
-    param_env: ParamEnv<'tcx>,
+    /// Previously encountered safe references.
+    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
+    /// A list of all encountered allocations. After type-based interning, we traverse this list to
+    /// also intern allocations that are only referenced by a raw pointer or inside a union.
+    leftover_allocations: &'rt mut FxHashSet<AllocId>,
     /// The root node of the value that we're looking at. This field is never mutated and only used
     /// for sanity assertions that will ICE when `const_qualif` screws up.
     mode: InternMode,
     /// This field stores the mutability of the value *currently* being checked.
-    /// It is set to mutable when an `UnsafeCell` is encountered
-    /// When recursing across a reference, we don't recurse but store the
-    /// value to be checked in `ref_tracking` together with the mutability at which we are checking
-    /// the value.
-    /// When encountering an immutable reference, we treat everything as immutable that is behind
-    /// it.
+    /// When encountering a mutable reference, we determine the pointee mutability
+    /// taking into account the mutability of the context: `& &mut i32` is entirely immutable,
+    /// despite the nested mutable reference!
+    /// The field gets updated when an `UnsafeCell` is encountered.
     mutability: Mutability,
-    /// A list of all encountered relocations. After type-based interning, we traverse this list to
-    /// also intern allocations that are only referenced by a raw pointer or inside a union.
-    leftover_relocations: &'rt mut FxHashSet<AllocId>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
@@ -45,9 +42,10 @@
     /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mut`
     /// that will actually be treated as mutable.
     Static,
-    /// UnsafeCell is OK in the value of a constant, but not behind references in a constant
+    /// UnsafeCell is OK in the value of a constant: `const FOO = Cell::new(0)` creates
+    /// a new cell every time it is used.
     ConstBase,
-    /// `UnsafeCell` ICEs
+    /// `UnsafeCell` ICEs.
     Const,
 }
 
@@ -55,48 +53,100 @@
 /// into the memory of other constants or statics
 struct IsStaticOrFn;
 
+/// Intern an allocation without looking at its children.
+/// `mode` is the mode of the environment where we found this pointer.
+/// `mutablity` is the mutability of the place to be interned; even if that says
+/// `immutable` things might become mutable if `ty` is not frozen.
+/// `ty` can be `None` if there is no potential interior mutability
+/// to account for (e.g. for vtables).
+fn intern_shallow<'rt, 'mir, 'tcx>(
+    ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
+    leftover_allocations: &'rt mut FxHashSet<AllocId>,
+    mode: InternMode,
+    alloc_id: AllocId,
+    mutability: Mutability,
+    ty: Option<Ty<'tcx>>,
+) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
+    trace!(
+        "InternVisitor::intern {:?} with {:?}",
+        alloc_id, mutability,
+    );
+    // remove allocation
+    let tcx = ecx.tcx;
+    let memory = ecx.memory_mut();
+    let (kind, mut alloc) = match memory.alloc_map.remove(&alloc_id) {
+        Some(entry) => entry,
+        None => {
+            // Pointer not found in local memory map. It is either a pointer to the global
+            // map, or dangling.
+            // If the pointer is dangling (neither in local nor global memory), we leave it
+            // to validation to error. The `delay_span_bug` ensures that we don't forget such
+            // a check in validation.
+            if tcx.alloc_map.lock().get(alloc_id).is_none() {
+                tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
+            }
+            // treat dangling pointers like other statics
+            // just to stop trying to recurse into them
+            return Ok(Some(IsStaticOrFn));
+        },
+    };
+    // This match is just a canary for future changes to `MemoryKind`, which most likely need
+    // changes in this function.
+    match kind {
+        MemoryKind::Stack | MemoryKind::Vtable => {},
+    }
+    // Set allocation mutability as appropriate. This is used by LLVM to put things into
+    // read-only memory, and also by Miri when evluating other constants/statics that
+    // access this one.
+    if mode == InternMode::Static {
+        // When `ty` is `None`, we assume no interior mutability.
+        let frozen = ty.map_or(true, |ty| ty.is_freeze(
+            ecx.tcx.tcx,
+            ecx.param_env,
+            ecx.tcx.span,
+        ));
+        // For statics, allocation mutability is the combination of the place mutability and
+        // the type mutability.
+        // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
+        if mutability == Mutability::Immutable && frozen {
+            alloc.mutability = Mutability::Immutable;
+        } else {
+            // Just making sure we are not "upgrading" an immutable allocation to mutable.
+            assert_eq!(alloc.mutability, Mutability::Mutable);
+        }
+    } else {
+        // We *could* be non-frozen at `ConstBase`, for constants like `Cell::new(0)`.
+        // But we still intern that as immutable as the memory cannot be changed once the
+        // initial value was computed.
+        // Constants are never mutable.
+        assert_eq!(
+            mutability, Mutability::Immutable,
+            "Something went very wrong: mutability requested for a constant"
+        );
+        alloc.mutability = Mutability::Immutable;
+    };
+    // link the alloc id to the actual allocation
+    let alloc = tcx.intern_const_alloc(alloc);
+    leftover_allocations.extend(alloc.relocations().iter().map(|&(_, ((), reloc))| reloc));
+    tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
+    Ok(None)
+}
+
 impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
-    /// Intern an allocation without looking at its children
     fn intern_shallow(
         &mut self,
-        ptr: Pointer,
+        alloc_id: AllocId,
         mutability: Mutability,
+        ty: Option<Ty<'tcx>>,
     ) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
-        trace!(
-            "InternVisitor::intern {:?} with {:?}",
-            ptr, mutability,
-        );
-        // remove allocation
-        let tcx = self.ecx.tcx;
-        let memory = self.ecx.memory_mut();
-        let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
-            Some(entry) => entry,
-            None => {
-                // if the pointer is dangling (neither in local nor global memory), we leave it
-                // to validation to error. The `delay_span_bug` ensures that we don't forget such
-                // a check in validation.
-                if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
-                    tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
-                }
-                // treat dangling pointers like other statics
-                // just to stop trying to recurse into them
-                return Ok(Some(IsStaticOrFn));
-            },
-        };
-        // This match is just a canary for future changes to `MemoryKind`, which most likely need
-        // changes in this function.
-        match kind {
-            MemoryKind::Stack | MemoryKind::Vtable => {},
-        }
-        // Ensure llvm knows to only put this into immutable memory if the value is immutable either
-        // by being behind a reference or by being part of a static or const without interior
-        // mutability
-        alloc.mutability = mutability;
-        // link the alloc id to the actual allocation
-        let alloc = tcx.intern_const_alloc(alloc);
-        self.leftover_relocations.extend(alloc.relocations().iter().map(|&(_, ((), reloc))| reloc));
-        tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
-        Ok(None)
+        intern_shallow(
+            self.ecx,
+            self.leftover_allocations,
+            self.mode,
+            alloc_id,
+            mutability,
+            ty,
+        )
     }
 }
 
@@ -119,14 +169,16 @@
     ) -> InterpResult<'tcx> {
         if let Some(def) = mplace.layout.ty.ty_adt_def() {
             if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
-                // We are crossing over an `UnsafeCell`, we can mutate again
+                // We are crossing over an `UnsafeCell`, we can mutate again. This means that
+                // References we encounter inside here are interned as pointing to mutable
+                // allocations.
                 let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
                 assert_ne!(
                     self.mode, InternMode::Const,
                     "UnsafeCells are not allowed behind references in constants. This should have \
                     been prevented statically by const qualification. If this were allowed one \
-                    would be able to change a constant at one use site and other use sites may \
-                    arbitrarily decide to change, too.",
+                    would be able to change a constant at one use site and other use sites could \
+                    observe that mutation.",
                 );
                 let walked = self.walk_aggregate(mplace, fields);
                 self.mutability = old;
@@ -145,12 +197,13 @@
             // Handle trait object vtables
             if let Ok(meta) = value.to_meta() {
                 if let ty::Dynamic(..) =
-                    self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.param_env).sty
+                    self.ecx.tcx.struct_tail_erasing_lifetimes(
+                        referenced_ty, self.ecx.param_env).sty
                 {
                     if let Ok(vtable) = meta.unwrap().to_ptr() {
                         // explitly choose `Immutable` here, since vtables are immutable, even
                         // if the reference of the fat pointer is mutable
-                        self.intern_shallow(vtable, Mutability::Immutable)?;
+                        self.intern_shallow(vtable.alloc_id, Mutability::Immutable, None)?;
                     }
                 }
             }
@@ -177,7 +230,7 @@
                     (InternMode::Const, hir::Mutability::MutMutable) => {
                         match referenced_ty.sty {
                             ty::Array(_, n)
-                                if n.eval_usize(self.ecx.tcx.tcx, self.param_env) == 0 => {}
+                                if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {}
                             ty::Slice(_)
                                 if value.to_meta().unwrap().unwrap().to_usize(self.ecx)? == 0 => {}
                             _ => bug!("const qualif failed to prevent mutable references"),
@@ -195,21 +248,13 @@
                     (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
                     _ => Mutability::Immutable,
                 };
-                // Compute the mutability of the allocation
-                let intern_mutability = intern_mutability(
-                    self.ecx.tcx.tcx,
-                    self.param_env,
-                    mplace.layout.ty,
-                    self.ecx.tcx.span,
-                    mutability,
-                );
                 // Recursing behind references changes the intern mode for constants in order to
                 // cause assertions to trigger if we encounter any `UnsafeCell`s.
                 let mode = match self.mode {
                     InternMode::ConstBase => InternMode::Const,
                     other => other,
                 };
-                match self.intern_shallow(ptr, intern_mutability)? {
+                match self.intern_shallow(ptr.alloc_id, mutability, Some(mplace.layout.ty))? {
                     // No need to recurse, these are interned already and statics may have
                     // cycles, so we don't want to recurse there
                     Some(IsStaticOrFn) => {},
@@ -224,69 +269,45 @@
     }
 }
 
-/// Figure out the mutability of the allocation.
-/// Mutable if it has interior mutability *anywhere* in the type.
-fn intern_mutability<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    span: Span,
-    mutability: Mutability,
-) -> Mutability {
-    let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
-    if has_interior_mutability {
-        Mutability::Mutable
-    } else {
-        mutability
-    }
-}
-
 pub fn intern_const_alloc_recursive(
     ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
     def_id: DefId,
     ret: MPlaceTy<'tcx>,
-    // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
-    // must always be monomorphic, right?
-    param_env: ty::ParamEnv<'tcx>,
 ) -> InterpResult<'tcx> {
     let tcx = ecx.tcx;
     // this `mutability` is the mutability of the place, ignoring the type
-    let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
+    let (base_mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
         Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
-        None => (Mutability::Immutable, InternMode::ConstBase),
         // `static mut` doesn't care about interior mutability, it's mutable anyway
         Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
+        // consts, promoteds. FIXME: what about array lengths, array initializers?
+        None => (Mutability::Immutable, InternMode::ConstBase),
     };
 
-    // type based interning
-    let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
-    let leftover_relocations = &mut FxHashSet::default();
-
-    // This mutability is the combination of the place mutability and the type mutability. If either
-    // is mutable, `alloc_mutability` is mutable. This exists because the entire allocation needs
-    // to be mutable if it contains an `UnsafeCell` anywhere. The other `mutability` exists so that
-    // the visitor does not treat everything outside the `UnsafeCell` as mutable.
-    let alloc_mutability = intern_mutability(
-        tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
-    );
+    // Type based interning.
+    // `ref_tracking` tracks typed references we have seen and still need to crawl for
+    // more typed information inside them.
+    // `leftover_allocations` collects *all* allocations we see, because some might not
+    // be available in a typed way. They get interned at the end.
+    let mut ref_tracking = RefTracking::new((ret, base_mutability, base_intern_mode));
+    let leftover_allocations = &mut FxHashSet::default();
 
     // start with the outermost allocation
-    InternVisitor {
-        ref_tracking: &mut ref_tracking,
+    intern_shallow(
         ecx,
-        mode: base_intern_mode,
-        leftover_relocations,
-        param_env,
-        mutability,
-    }.intern_shallow(ret.ptr.to_ptr()?, alloc_mutability)?;
+        leftover_allocations,
+        base_intern_mode,
+        ret.ptr.to_ptr()?.alloc_id,
+        base_mutability,
+        Some(ret.layout.ty)
+    )?;
 
     while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
         let interned = InternVisitor {
             ref_tracking: &mut ref_tracking,
             ecx,
             mode,
-            leftover_relocations,
-            param_env,
+            leftover_allocations,
             mutability,
         }.visit_value(mplace);
         if let Err(error) = interned {
@@ -309,15 +330,23 @@
     // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
     // pointers, ... So we can't intern them according to their type rules
 
-    let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
+    let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect();
     while let Some(alloc_id) = todo.pop() {
-        if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
-            // We can't call the `intern` method here, as its logic is tailored to safe references.
-            // So we hand-roll the interning logic here again
+        if let Some((_, mut alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
+            // We can't call the `intern_shallow` method here, as its logic is tailored to safe
+            // references and a `leftover_allocations` set (where we only have a todo-list here).
+            // So we hand-roll the interning logic here again.
+            if base_intern_mode != InternMode::Static {
+                // If it's not a static, it *must* be immutable.
+                // We cannot have mutable memory inside a constant.
+                // FIXME: ideally we would assert that they already are immutable, to double-
+                // check our static checks.
+                alloc.mutability = Mutability::Immutable;
+            }
             let alloc = tcx.intern_const_alloc(alloc);
             tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
             for &(_, ((), reloc)) in alloc.relocations().iter() {
-                if leftover_relocations.insert(reloc) {
+                if leftover_allocations.insert(reloc) {
                     todo.push(reloc);
                 }
             }
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 0f2305e..ec09e69 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -5,17 +5,18 @@
 use syntax::symbol::Symbol;
 use rustc::ty;
 use rustc::ty::layout::{LayoutOf, Primitive, Size};
+use rustc::ty::subst::SubstsRef;
+use rustc::hir::def_id::DefId;
+use rustc::ty::TyCtxt;
 use rustc::mir::BinOp;
-use rustc::mir::interpret::{InterpResult, Scalar};
+use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue};
 
 use super::{
-    Machine, PlaceTy, OpTy, InterpCx, Immediate,
+    Machine, PlaceTy, OpTy, InterpCx,
 };
 
 mod type_name;
 
-pub use type_name::*;
-
 fn numeric_intrinsic<'tcx, Tag>(
     name: &str,
     bits: u128,
@@ -37,6 +38,50 @@
     Ok(Scalar::from_uint(bits_out, size))
 }
 
+/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
+/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
+crate fn eval_nullary_intrinsic<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    def_id: DefId,
+    substs: SubstsRef<'tcx>,
+) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
+    let tp_ty = substs.type_at(0);
+    let name = &*tcx.item_name(def_id).as_str();
+    Ok(match name {
+        "type_name" => {
+            let alloc = type_name::alloc_type_name(tcx, tp_ty);
+            tcx.mk_const(ty::Const {
+                val: ConstValue::Slice {
+                    data: alloc,
+                    start: 0,
+                    end: alloc.len(),
+                },
+                ty: tcx.mk_static_str(),
+            })
+        },
+        "needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
+        "size_of" |
+        "min_align_of" |
+        "pref_align_of" => {
+            let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
+            let n = match name {
+                "pref_align_of" => layout.align.pref.bytes(),
+                "min_align_of" => layout.align.abi.bytes(),
+                "size_of" => layout.size.bytes(),
+                _ => bug!(),
+            };
+            ty::Const::from_usize(tcx, n)
+        },
+        "type_id" => ty::Const::from_bits(
+            tcx,
+            tcx.type_id_hash(tp_ty).into(),
+            param_env.and(tcx.types.u64),
+        ),
+        other => bug!("`{}` is not a zero arg intrinsic", other),
+    })
+}
+
 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Returns `true` if emulation happened.
     pub fn emulate_intrinsic(
@@ -49,41 +94,19 @@
 
         let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
         match intrinsic_name {
-            "min_align_of" => {
-                let elem_ty = substs.type_at(0);
-                let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
-                let align_val = Scalar::from_uint(elem_align, dest.layout.size);
-                self.write_scalar(align_val, dest)?;
-            }
-
-            "needs_drop" => {
-                let ty = substs.type_at(0);
-                let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
-                let val = Scalar::from_bool(ty_needs_drop);
-                self.write_scalar(val, dest)?;
-            }
-
-            "size_of" => {
-                let ty = substs.type_at(0);
-                let size = self.layout_of(ty)?.size.bytes() as u128;
-                let size_val = Scalar::from_uint(size, dest.layout.size);
-                self.write_scalar(size_val, dest)?;
-            }
-
-            "type_id" => {
-                let ty = substs.type_at(0);
-                let type_id = self.tcx.type_id_hash(ty) as u128;
-                let id_val = Scalar::from_uint(type_id, dest.layout.size);
-                self.write_scalar(id_val, dest)?;
-            }
-
+            "min_align_of" |
+            "pref_align_of" |
+            "needs_drop" |
+            "size_of" |
+            "type_id" |
             "type_name" => {
-                let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0));
-                let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
-                let id_ptr = self.memory.tag_static_base_pointer(name_id.into());
-                let alloc_len = alloc.size.bytes();
-                let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self);
-                self.write_immediate(name_val, dest)?;
+                let gid = GlobalId {
+                    instance,
+                    promoted: None,
+                };
+                let val = self.tcx.const_eval(self.param_env.and(gid))?;
+                let val = self.eval_const_to_op(val, None)?;
+                self.copy_op(val, dest)?;
             }
 
             | "ctpop"
diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs
index 032d16a..1e765a4 100644
--- a/src/librustc_mir/interpret/intrinsics/type_name.rs
+++ b/src/librustc_mir/interpret/intrinsics/type_name.rs
@@ -7,7 +7,7 @@
 use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
 use rustc::hir::def_id::CrateNum;
 use std::fmt::Write;
-use rustc::mir::interpret::{Allocation, ConstValue};
+use rustc::mir::interpret::Allocation;
 
 struct AbsolutePathPrinter<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -213,22 +213,11 @@
     }
 }
 
-/// Produces an absolute path representation of the given type. See also the documentation on
-/// `std::any::type_name`
-pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
-    let alloc = alloc_type_name(tcx, ty);
-    tcx.mk_const(ty::Const {
-        val: ConstValue::Slice {
-            data: alloc,
-            start: 0,
-            end: alloc.len(),
-        },
-        ty: tcx.mk_static_str(),
-    })
-}
-
 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
-pub(super) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
+crate fn alloc_type_name<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>
+) -> &'tcx Allocation {
     let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
     let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
     tcx.intern_const_alloc(alloc)
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 45d2434..0c61be2 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -34,6 +34,6 @@
 
 pub use self::validity::RefTracking;
 
-pub(super) use self::intrinsics::type_name;
-
 pub use self::intern::intern_const_alloc_recursive;
+
+crate use self::intrinsics::eval_nullary_intrinsic;
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index b5aab99..9ad1542 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -472,39 +472,38 @@
     // avoid allocations.
     pub(super) fn eval_place_to_op(
         &self,
-        mir_place: &mir::Place<'tcx>,
+        place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc::mir::PlaceBase;
 
-        mir_place.iterate(|place_base, place_projection| {
-            let mut op = match place_base {
-                PlaceBase::Local(mir::RETURN_PLACE) =>
-                    throw_unsup!(ReadFromReturnPointer),
-                PlaceBase::Local(local) => {
-                    // Do not use the layout passed in as argument if the base we are looking at
-                    // here is not the entire place.
-                    // FIXME use place_projection.is_empty() when is available
-                    let layout = if mir_place.projection.is_none() {
-                        layout
-                    } else {
-                        None
-                    };
+        let base_op = match &place.base {
+            PlaceBase::Local(mir::RETURN_PLACE) =>
+                throw_unsup!(ReadFromReturnPointer),
+            PlaceBase::Local(local) => {
+                // Do not use the layout passed in as argument if the base we are looking at
+                // here is not the entire place.
+                // FIXME use place_projection.is_empty() when is available
+                let layout = if place.projection.is_empty() {
+                    layout
+                } else {
+                    None
+                };
 
-                    self.access_local(self.frame(), *local, layout)?
-                }
-                PlaceBase::Static(place_static) => {
-                    self.eval_static_to_mplace(place_static)?.into()
-                }
-            };
-
-            for proj in place_projection {
-                op = self.operand_projection(op, &proj.elem)?
+                self.access_local(self.frame(), *local, layout)?
             }
+            PlaceBase::Static(place_static) => {
+                self.eval_static_to_mplace(&place_static)?.into()
+            }
+        };
 
-            trace!("eval_place_to_op: got {:?}", *op);
-            Ok(op)
-        })
+        let op = place.projection.iter().try_fold(
+            base_op,
+            |op, elem| self.operand_projection(op, elem)
+        )?;
+
+        trace!("eval_place_to_op: got {:?}", *op);
+        Ok(op)
     }
 
     /// Evaluate the operand, returning a place where you can then find the data.
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index f358bb0..1a28548 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -629,45 +629,43 @@
     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
     pub fn eval_place(
         &mut self,
-        mir_place: &mir::Place<'tcx>,
+        place: &mir::Place<'tcx>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::PlaceBase;
 
-        mir_place.iterate(|place_base, place_projection| {
-            let mut place = match place_base {
-                PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
-                    Some(return_place) => {
-                        // We use our layout to verify our assumption; caller will validate
-                        // their layout on return.
-                        PlaceTy {
-                            place: *return_place,
-                            layout: self.layout_of(
-                                self.subst_from_frame_and_normalize_erasing_regions(
-                                    self.frame().body.return_ty()
-                                )
-                            )?,
-                        }
+        let mut place_ty = match &place.base {
+            PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
+                Some(return_place) => {
+                    // We use our layout to verify our assumption; caller will validate
+                    // their layout on return.
+                    PlaceTy {
+                        place: *return_place,
+                        layout: self.layout_of(
+                            self.subst_from_frame_and_normalize_erasing_regions(
+                                self.frame().body.return_ty()
+                            )
+                        )?,
                     }
-                    None => throw_unsup!(InvalidNullPointerUsage),
+                }
+                None => throw_unsup!(InvalidNullPointerUsage),
+            },
+            PlaceBase::Local(local) => PlaceTy {
+                // This works even for dead/uninitialized locals; we check further when writing
+                place: Place::Local {
+                    frame: self.cur_frame(),
+                    local: *local,
                 },
-                PlaceBase::Local(local) => PlaceTy {
-                    // This works even for dead/uninitialized locals; we check further when writing
-                    place: Place::Local {
-                        frame: self.cur_frame(),
-                        local: *local,
-                    },
-                    layout: self.layout_of_local(self.frame(), *local, None)?,
-                },
-                PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(),
-            };
+                layout: self.layout_of_local(self.frame(), *local, None)?,
+            },
+            PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
+        };
 
-            for proj in place_projection {
-                place = self.place_projection(place, &proj.elem)?
-            }
+        for elem in place.projection.iter() {
+            place_ty = self.place_projection(place_ty, elem)?
+        }
 
-            self.dump_place(place.place);
-            Ok(place)
-        })
+        self.dump_place(place_ty.place);
+        Ok(place_ty)
     }
 
     /// Write a scalar to a place
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index ca4da45..affca10 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -82,7 +82,7 @@
         self.memory.tcx.span = stmt.source_info.span;
 
         match stmt.kind {
-            Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
+            Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,
 
             SetDiscriminant {
                 ref place,
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 5de2979..8310ef0 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -391,7 +391,7 @@
                     // Don't forget to check the return type!
                     if let Some(caller_ret) = dest {
                         let callee_ret = self.eval_place(
-                            &mir::Place::RETURN_PLACE
+                            &mir::Place::return_place()
                         )?;
                         if !Self::check_argument_compat(
                             rust_abi,
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index f27db35..034ad5b 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -59,5 +59,4 @@
         let (param_env, (value, field)) = param_env_and_value.into_parts();
         const_eval::const_field(tcx, param_env, None, field, value)
     };
-    providers.type_name = interpret::type_name;
 }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index aa83255..6daca5e 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -217,7 +217,7 @@
             // Function arguments should be retagged, and we make this one raw.
             body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
                 source_info,
-                kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()),
+                kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())),
             });
         }
         let patch = {
@@ -308,7 +308,7 @@
     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
     let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
 
-    let dest = Place::RETURN_PLACE;
+    let dest = Place::return_place();
     let src = Place::from(Local::new(1+0)).deref();
 
     match self_ty.sty {
@@ -415,8 +415,10 @@
         let rcvr = Place::from(Local::new(1+0)).deref();
         let ret_statement = self.make_statement(
             StatementKind::Assign(
-                Place::RETURN_PLACE,
-                box Rvalue::Use(Operand::Copy(rcvr))
+                box(
+                    Place::return_place(),
+                    Rvalue::Use(Operand::Copy(rcvr))
+                )
             )
         );
         self.block(vec![ret_statement], TerminatorKind::Return, false);
@@ -458,8 +460,10 @@
         // `let ref_loc: &ty = &src;`
         let statement = self.make_statement(
             StatementKind::Assign(
-                ref_loc.clone(),
-                box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
+                box(
+                    ref_loc.clone(),
+                    Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
+                )
             )
         );
 
@@ -486,8 +490,10 @@
         let cond = self.make_place(Mutability::Mut, tcx.types.bool);
         let compute_cond = self.make_statement(
             StatementKind::Assign(
-                cond.clone(),
-                box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
+                box(
+                    cond.clone(),
+                    Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
+                )
             )
         );
 
@@ -521,14 +527,18 @@
         let inits = vec![
             self.make_statement(
                 StatementKind::Assign(
-                    Place::from(beg),
-                    box Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                    box(
+                        Place::from(beg),
+                        Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                    )
                 )
             ),
             self.make_statement(
                 StatementKind::Assign(
-                    end.clone(),
-                    box Rvalue::Use(Operand::Constant(self.make_usize(len)))
+                    box(
+                        end.clone(),
+                        Rvalue::Use(Operand::Constant(self.make_usize(len)))
+                    )
                 )
             )
         ];
@@ -559,11 +569,13 @@
         let statements = vec![
             self.make_statement(
                 StatementKind::Assign(
-                    Place::from(beg),
-                    box Rvalue::BinaryOp(
-                        BinOp::Add,
-                        Operand::Copy(Place::from(beg)),
-                        Operand::Constant(self.make_usize(1))
+                    box(
+                        Place::from(beg),
+                        Rvalue::BinaryOp(
+                            BinOp::Add,
+                            Operand::Copy(Place::from(beg)),
+                            Operand::Constant(self.make_usize(1))
+                        )
                     )
                 )
             )
@@ -582,8 +594,10 @@
         let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
         let init = self.make_statement(
             StatementKind::Assign(
-                Place::from(beg),
-                box Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                box(
+                    Place::from(beg),
+                    Rvalue::Use(Operand::Constant(self.make_usize(0)))
+                )
             )
         );
         self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
@@ -609,11 +623,13 @@
         // `goto #6;`
         let statement = self.make_statement(
             StatementKind::Assign(
-                Place::from(beg),
-                box Rvalue::BinaryOp(
-                    BinOp::Add,
-                    Operand::Copy(Place::from(beg)),
-                    Operand::Constant(self.make_usize(1))
+                box(
+                    Place::from(beg),
+                    Rvalue::BinaryOp(
+                        BinOp::Add,
+                        Operand::Copy(Place::from(beg)),
+                        Operand::Constant(self.make_usize(1))
+                    )
                 )
             )
         );
@@ -727,8 +743,10 @@
             statements.push(Statement {
                 source_info,
                 kind: StatementKind::Assign(
-                    Place::from(ref_rcvr),
-                    box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
+                    box(
+                        Place::from(ref_rcvr),
+                        Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
+                    )
                 )
             });
             Operand::Move(Place::from(ref_rcvr))
@@ -773,7 +791,7 @@
     block(&mut blocks, statements, TerminatorKind::Call {
         func: callee,
         args,
-        destination: Some((Place::RETURN_PLACE,
+        destination: Some((Place::return_place(),
                            BasicBlock::new(1))),
         cleanup: if let Adjustment::RefMut = rcvr_adjustment {
             Some(BasicBlock::new(3))
@@ -868,7 +886,7 @@
     debug!("build_ctor: variant_index={:?}", variant_index);
 
     let statements = expand_aggregate(
-        Place::RETURN_PLACE,
+        Place::return_place(),
         adt_def
             .variants[variant_index]
             .fields
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index 0fd75cd..833c8b1 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -17,12 +17,11 @@
 fn is_stable(
     place: PlaceRef<'_, '_>,
 ) -> bool {
-    if let Some(proj) = &place.projection {
-        match proj.elem {
+    place.projection.iter().all(|elem| {
+        match elem {
             // Which place this evaluates to can change with any memory write,
             // so cannot assume this to be stable.
-            ProjectionElem::Deref =>
-                false,
+            ProjectionElem::Deref => false,
             // Array indices are intersting, but MIR building generates a *fresh*
             // temporary for every array access, so the index cannot be changed as
             // a side-effect.
@@ -31,15 +30,9 @@
             ProjectionElem::Field { .. } |
             ProjectionElem::ConstantIndex { .. } |
             ProjectionElem::Subslice { .. } |
-            ProjectionElem::Downcast { .. } =>
-                is_stable(PlaceRef {
-                    base: place.base,
-                    projection: &proj.base,
-                }),
+            ProjectionElem::Downcast { .. } => true,
         }
-    } else {
-        true
-    }
+    })
 }
 
 /// Determine whether this type may be a reference (or box), and thus needs retagging.
@@ -96,7 +89,7 @@
             basic_blocks[START_BLOCK].statements.splice(0..0,
                 places.into_iter().map(|place| Statement {
                     source_info,
-                    kind: StatementKind::Retag(RetagKind::FnEntry, place),
+                    kind: StatementKind::Retag(RetagKind::FnEntry, box(place)),
                 })
             );
         }
@@ -132,7 +125,7 @@
         for (source_info, dest_place, dest_block) in returns {
             basic_blocks[dest_block].statements.insert(0, Statement {
                 source_info,
-                kind: StatementKind::Retag(RetagKind::Default, dest_place),
+                kind: StatementKind::Retag(RetagKind::Default, box(dest_place)),
             });
         }
 
@@ -144,11 +137,11 @@
             for i in (0..block_data.statements.len()).rev() {
                 let (retag_kind, place) = match block_data.statements[i].kind {
                     // If we are casting *from* a reference, we may have to retag-as-raw.
-                    StatementKind::Assign(ref place, box Rvalue::Cast(
+                    StatementKind::Assign(box(ref place, Rvalue::Cast(
                         CastKind::Misc,
                         ref src,
                         dest_ty,
-                    )) => {
+                    ))) => {
                         let src_ty = src.ty(&*local_decls, tcx);
                         if src_ty.is_region_ptr() {
                             // The only `Misc` casts on references are those creating raw pointers.
@@ -162,7 +155,7 @@
                     // Assignments of reference or ptr type are the ones where we may have
                     // to update tags.  This includes `x = &[mut] ...` and hence
                     // we also retag after taking a reference!
-                    StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => {
+                    StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => {
                         let kind = match rvalue {
                             Rvalue::Ref(_, borrow_kind, _)
                                 if borrow_kind.allows_two_phase_borrow()
@@ -180,7 +173,7 @@
                 let source_info = block_data.statements[i].source_info;
                 block_data.statements.insert(i+1, Statement {
                     source_info,
-                    kind: StatementKind::Retag(retag_kind, place),
+                    kind: StatementKind::Retag(retag_kind, box(place)),
                 });
             }
         }
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 539922c..39aa5c7 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -200,127 +200,127 @@
                     place: &Place<'tcx>,
                     context: PlaceContext,
                     _location: Location) {
-        place.iterate(|place_base, place_projections| {
-            match place_base {
-                PlaceBase::Local(..) => {
-                    // Locals are safe.
-                }
-                PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
-                    bug!("unsafety checking should happen before promotion")
-                }
-                PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
-                    if self.tcx.is_mutable_static(*def_id) {
-                        self.require_unsafe("use of mutable static",
-                            "mutable statics can be mutated by multiple threads: aliasing \
-                             violations or data races will cause undefined behavior",
-                             UnsafetyViolationKind::General);
-                    } else if self.tcx.is_foreign_item(*def_id) {
-                        let source_info = self.source_info;
-                        let lint_root =
-                            self.source_scope_local_data[source_info.scope].lint_root;
-                        self.register_violations(&[UnsafetyViolation {
-                            source_info,
-                            description: InternedString::intern("use of extern static"),
-                            details: InternedString::intern(
-                                "extern statics are not controlled by the Rust type system: \
-                                invalid data, aliasing violations or data races will cause \
-                                undefined behavior"),
-                            kind: UnsafetyViolationKind::ExternStatic(lint_root)
-                        }], &[]);
-                    }
+        match place.base {
+            PlaceBase::Local(..) => {
+                // Locals are safe.
+            }
+            PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
+                bug!("unsafety checking should happen before promotion")
+            }
+            PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
+                if self.tcx.is_mutable_static(def_id) {
+                    self.require_unsafe("use of mutable static",
+                        "mutable statics can be mutated by multiple threads: aliasing \
+                         violations or data races will cause undefined behavior",
+                         UnsafetyViolationKind::General);
+                } else if self.tcx.is_foreign_item(def_id) {
+                    let source_info = self.source_info;
+                    let lint_root =
+                        self.source_scope_local_data[source_info.scope].lint_root;
+                    self.register_violations(&[UnsafetyViolation {
+                        source_info,
+                        description: InternedString::intern("use of extern static"),
+                        details: InternedString::intern(
+                            "extern statics are not controlled by the Rust type system: \
+                            invalid data, aliasing violations or data races will cause \
+                            undefined behavior"),
+                        kind: UnsafetyViolationKind::ExternStatic(lint_root)
+                    }], &[]);
                 }
             }
+        }
 
-            for proj in place_projections {
-                if context.is_borrow() {
-                    if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
-                        let source_info = self.source_info;
-                        let lint_root =
-                            self.source_scope_local_data[source_info.scope].lint_root;
-                        self.register_violations(&[UnsafetyViolation {
-                            source_info,
-                            description: InternedString::intern("borrow of packed field"),
-                            details: InternedString::intern(
-                                "fields of packed structs might be misaligned: dereferencing a \
-                                misaligned pointer or even just creating a misaligned reference \
-                                is undefined behavior"),
-                            kind: UnsafetyViolationKind::BorrowPacked(lint_root)
-                        }], &[]);
-                    }
+        for (i, elem) in place.projection.iter().enumerate() {
+            let proj_base = &place.projection[..i];
+
+            if context.is_borrow() {
+                if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
+                    let source_info = self.source_info;
+                    let lint_root =
+                        self.source_scope_local_data[source_info.scope].lint_root;
+                    self.register_violations(&[UnsafetyViolation {
+                        source_info,
+                        description: InternedString::intern("borrow of packed field"),
+                        details: InternedString::intern(
+                            "fields of packed structs might be misaligned: dereferencing a \
+                            misaligned pointer or even just creating a misaligned reference \
+                            is undefined behavior"),
+                        kind: UnsafetyViolationKind::BorrowPacked(lint_root)
+                    }], &[]);
                 }
-                let is_borrow_of_interior_mut = context.is_borrow() &&
-                    !Place::ty_from(&place.base, &proj.base, self.body, self.tcx)
-                    .ty
-                    .is_freeze(self.tcx, self.param_env, self.source_info.span);
-                // prevent
-                // * `&mut x.field`
-                // * `x.field = y;`
-                // * `&x.field` if `field`'s type has interior mutability
-                // because either of these would allow modifying the layout constrained field and
-                // insert values that violate the layout constraints.
-                if context.is_mutating_use() || is_borrow_of_interior_mut {
-                    self.check_mut_borrowing_layout_constrained_field(
-                        place, context.is_mutating_use(),
-                    );
+            }
+            let is_borrow_of_interior_mut = context.is_borrow() &&
+                !Place::ty_from(&place.base, proj_base, self.body, self.tcx)
+                .ty
+                .is_freeze(self.tcx, self.param_env, self.source_info.span);
+            // prevent
+            // * `&mut x.field`
+            // * `x.field = y;`
+            // * `&x.field` if `field`'s type has interior mutability
+            // because either of these would allow modifying the layout constrained field and
+            // insert values that violate the layout constraints.
+            if context.is_mutating_use() || is_borrow_of_interior_mut {
+                self.check_mut_borrowing_layout_constrained_field(
+                    place, context.is_mutating_use(),
+                );
+            }
+            let old_source_info = self.source_info;
+            if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
+                if self.body.local_decls[*local].internal {
+                    // Internal locals are used in the `move_val_init` desugaring.
+                    // We want to check unsafety against the source info of the
+                    // desugaring, rather than the source info of the RHS.
+                    self.source_info = self.body.local_decls[*local].source_info;
                 }
-                let old_source_info = self.source_info;
-                if let (PlaceBase::Local(local), None) = (&place.base, &proj.base) {
-                    if self.body.local_decls[*local].internal {
-                        // Internal locals are used in the `move_val_init` desugaring.
-                        // We want to check unsafety against the source info of the
-                        // desugaring, rather than the source info of the RHS.
-                        self.source_info = self.body.local_decls[*local].source_info;
-                    }
+            }
+            let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
+            match base_ty.sty {
+                ty::RawPtr(..) => {
+                    self.require_unsafe("dereference of raw pointer",
+                        "raw pointers may be NULL, dangling or unaligned; they can violate \
+                         aliasing rules and cause data races: all of these are undefined \
+                         behavior", UnsafetyViolationKind::General)
                 }
-                let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
-                match base_ty.sty {
-                    ty::RawPtr(..) => {
-                        self.require_unsafe("dereference of raw pointer",
-                            "raw pointers may be NULL, dangling or unaligned; they can violate \
-                             aliasing rules and cause data races: all of these are undefined \
-                             behavior", UnsafetyViolationKind::General)
-                    }
-                    ty::Adt(adt, _) => {
-                        if adt.is_union() {
-                            if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
-                                context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
-                                context == PlaceContext::MutatingUse(
-                                    MutatingUseContext::AsmOutput
-                                )
-                            {
-                                let elem_ty = match proj.elem {
-                                    ProjectionElem::Field(_, ty) => ty,
-                                    _ => span_bug!(
-                                        self.source_info.span,
-                                        "non-field projection {:?} from union?",
-                                        place)
-                                };
-                                if !elem_ty.is_copy_modulo_regions(
-                                    self.tcx,
-                                    self.param_env,
+                ty::Adt(adt, _) => {
+                    if adt.is_union() {
+                        if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
+                            context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
+                            context == PlaceContext::MutatingUse(
+                                MutatingUseContext::AsmOutput
+                            )
+                        {
+                            let elem_ty = match elem {
+                                ProjectionElem::Field(_, ty) => ty,
+                                _ => span_bug!(
                                     self.source_info.span,
-                                ) {
-                                    self.require_unsafe(
-                                        "assignment to non-`Copy` union field",
-                                        "the previous content of the field will be dropped, which \
-                                         causes undefined behavior if the field was not properly \
-                                         initialized", UnsafetyViolationKind::General)
-                                } else {
-                                    // write to non-move union, safe
-                                }
+                                    "non-field projection {:?} from union?",
+                                    place)
+                            };
+                            if !elem_ty.is_copy_modulo_regions(
+                                self.tcx,
+                                self.param_env,
+                                self.source_info.span,
+                            ) {
+                                self.require_unsafe(
+                                    "assignment to non-`Copy` union field",
+                                    "the previous content of the field will be dropped, which \
+                                     causes undefined behavior if the field was not properly \
+                                     initialized", UnsafetyViolationKind::General)
                             } else {
-                                self.require_unsafe("access to union field",
-                                    "the field may not be properly initialized: using \
-                                     uninitialized data will cause undefined behavior",
-                                     UnsafetyViolationKind::General)
+                                // write to non-move union, safe
                             }
+                        } else {
+                            self.require_unsafe("access to union field",
+                                "the field may not be properly initialized: using \
+                                 uninitialized data will cause undefined behavior",
+                                 UnsafetyViolationKind::General)
                         }
                     }
-                    _ => {}
                 }
-                self.source_info = old_source_info;
+                _ => {}
             }
-        });
+            self.source_info = old_source_info;
+        }
     }
 }
 
@@ -407,12 +407,14 @@
         place: &Place<'tcx>,
         is_mut_use: bool,
     ) {
-        let mut projection = &place.projection;
-        while let Some(proj) = projection {
-            match proj.elem {
+        let mut cursor = &*place.projection;
+        while let [proj_base @ .., elem] = cursor {
+            cursor = proj_base;
+
+            match elem {
                 ProjectionElem::Field(..) => {
                     let ty =
-                        Place::ty_from(&place.base, &proj.base, &self.body.local_decls, self.tcx)
+                        Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx)
                             .ty;
                     match ty.sty {
                         ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
@@ -447,7 +449,6 @@
                 }
                 _ => {}
             }
-            projection = &proj.base;
         }
     }
 }
diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index ede1cb6..ea17327 100644
--- a/src/librustc_mir/transform/cleanup_post_borrowck.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -39,7 +39,7 @@
                        location: Location) {
         match statement.kind {
             StatementKind::AscribeUserType(..)
-            | StatementKind::Assign(_, box Rvalue::Ref(_, BorrowKind::Shallow, _))
+            | StatementKind::Assign(box(_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
             | StatementKind::FakeRead(..) => statement.make_nop(),
             _ => (),
         }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index e4b1867..614d5d2 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -282,53 +282,53 @@
 
     fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
         trace!("eval_place(place={:?})", place);
-        place.iterate(|place_base, place_projection| {
-            let mut eval = match place_base {
-                PlaceBase::Local(loc) => self.get_const(*loc).clone()?,
-                PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
-                    let generics = self.tcx.generics_of(self.source.def_id());
-                    if generics.requires_monomorphization(self.tcx) {
-                        // FIXME: can't handle code with generics
-                        return None;
-                    }
-                    let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
-                    let instance = Instance::new(self.source.def_id(), substs);
-                    let cid = GlobalId {
-                        instance,
-                        promoted: Some(*promoted),
-                    };
-                    let res = self.use_ecx(source_info, |this| {
-                        this.ecx.const_eval_raw(cid)
-                    })?;
-                    trace!("evaluated promoted {:?} to {:?}", promoted, res);
-                    res.into()
+        let mut eval = match place.base {
+            PlaceBase::Local(loc) => self.get_const(loc).clone()?,
+            PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
+                let generics = self.tcx.generics_of(self.source.def_id());
+                if generics.requires_monomorphization(self.tcx) {
+                    // FIXME: can't handle code with generics
+                    return None;
                 }
-                _ => return None,
-            };
-
-            for proj in place_projection {
-                match proj.elem {
-                    ProjectionElem::Field(field, _) => {
-                        trace!("field proj on {:?}", proj.base);
-                        eval = self.use_ecx(source_info, |this| {
-                            this.ecx.operand_field(eval, field.index() as u64)
-                        })?;
-                    },
-                    ProjectionElem::Deref => {
-                        trace!("processing deref");
-                        eval = self.use_ecx(source_info, |this| {
-                            this.ecx.deref_operand(eval)
-                        })?.into();
-                    }
-                    // We could get more projections by using e.g., `operand_projection`,
-                    // but we do not even have the stack frame set up properly so
-                    // an `Index` projection would throw us off-track.
-                    _ => return None,
-                }
+                let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
+                let instance = Instance::new(self.source.def_id(), substs);
+                let cid = GlobalId {
+                    instance,
+                    promoted: Some(promoted),
+                };
+                let res = self.use_ecx(source_info, |this| {
+                    this.ecx.const_eval_raw(cid)
+                })?;
+                trace!("evaluated promoted {:?} to {:?}", promoted, res);
+                res.into()
             }
+            _ => return None,
+        };
 
-            Some(eval)
-        })
+        for (i, elem) in place.projection.iter().enumerate() {
+            let proj_base = &place.projection[..i];
+
+            match elem {
+                ProjectionElem::Field(field, _) => {
+                    trace!("field proj on {:?}", proj_base);
+                    eval = self.use_ecx(source_info, |this| {
+                        this.ecx.operand_field(eval, field.index() as u64)
+                    })?;
+                },
+                ProjectionElem::Deref => {
+                    trace!("processing deref");
+                    eval = self.use_ecx(source_info, |this| {
+                        this.ecx.deref_operand(eval)
+                    })?.into();
+                }
+                // We could get more projections by using e.g., `operand_projection`,
+                // but we do not even have the stack frame set up properly so
+                // an `Index` projection would throw us off-track.
+                _ => return None,
+            }
+        }
+
+        Some(eval)
     }
 
     fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
@@ -665,7 +665,7 @@
         location: Location,
     ) {
         trace!("visit_statement: {:?}", statement);
-        if let StatementKind::Assign(ref place, ref mut rval) = statement.kind {
+        if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind {
             let place_ty: Ty<'tcx> = place
                 .ty(&self.local_decls, self.tcx)
                 .ty;
@@ -673,7 +673,7 @@
                 if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
                     if let Place {
                         base: PlaceBase::Local(local),
-                        projection: None,
+                        projection: box [],
                     } = *place {
                         trace!("checking whether {:?} can be stored to {:?}", value, local);
                         if self.can_const_prop[local] {
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index f3a523a..28f97f4 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -94,11 +94,13 @@
                     // That use of the source must be an assignment.
                     match statement.kind {
                         StatementKind::Assign(
-                            Place {
-                                base: PlaceBase::Local(local),
-                                projection: None,
-                            },
-                            box Rvalue::Use(ref operand)
+                            box(
+                                Place {
+                                    base: PlaceBase::Local(local),
+                                    projection: box [],
+                                },
+                                Rvalue::Use(ref operand)
+                            )
                         ) if local == dest_local => {
                             let maybe_action = match *operand {
                                 Operand::Copy(ref src_place) |
@@ -148,24 +150,28 @@
             if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
                 match stmt.kind {
                     StatementKind::Assign(
-                        Place {
-                            base: PlaceBase::Local(local),
-                            projection: None,
-                        },
-                        box Rvalue::Use(Operand::Copy(Place {
-                            base: PlaceBase::Local(src_local),
-                            projection: None,
-                        })),
+                        box(
+                            Place {
+                                base: PlaceBase::Local(local),
+                                projection: box [],
+                            },
+                            Rvalue::Use(Operand::Copy(Place {
+                                base: PlaceBase::Local(src_local),
+                                projection: box [],
+                            })),
+                        )
                     ) |
                     StatementKind::Assign(
-                        Place {
-                            base: PlaceBase::Local(local),
-                            projection: None,
-                        },
-                        box Rvalue::Use(Operand::Move(Place {
-                            base: PlaceBase::Local(src_local),
-                            projection: None,
-                        })),
+                        box(
+                            Place {
+                                base: PlaceBase::Local(local),
+                                projection: box [],
+                            },
+                            Rvalue::Use(Operand::Move(Place {
+                                base: PlaceBase::Local(src_local),
+                                projection: box [],
+                            })),
+                        )
                     ) if local == dest_local && dest_local == src_local => {}
                     _ => {
                         continue;
@@ -194,7 +200,7 @@
         // The source must be a local.
         let src_local = if let Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         } = *src_place {
             local
         } else {
@@ -351,11 +357,11 @@
         match *operand {
             Operand::Copy(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) |
             Operand::Move(Place {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: box [],
             }) if local == self.dest_local => {}
             _ => return,
         }
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index 1fc7ce0..c1224be 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -12,8 +12,8 @@
         for bb in basic_blocks {
             bb.expand_statements(|stmt| {
                 // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
-                if let StatementKind::Assign(_, ref rhs) = stmt.kind {
-                    if let Rvalue::Aggregate(ref kind, _) = **rhs {
+                if let StatementKind::Assign(box(_, ref rhs)) = stmt.kind {
+                    if let Rvalue::Aggregate(ref kind, _) = *rhs {
                         // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
                         if let AggregateKind::Array(_) = **kind {
                             return None;
@@ -28,7 +28,7 @@
                 let stmt = stmt.replace_nop();
                 let source_info = stmt.source_info;
                 let (lhs, kind, operands) = match stmt.kind {
-                    StatementKind::Assign(lhs, box rvalue) => {
+                    StatementKind::Assign(box(lhs, rvalue)) => {
                         match rvalue {
                             Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
                             _ => bug!()
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 7a5c00c..a9c66b3 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -236,47 +236,34 @@
     }
 
     fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection {
-                    elem: ProjectionElem::Field(idx, _), ..
-                } => idx == field,
-                _ => false
-            }
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+            ProjectionElem::Field(idx, _) => *idx == field,
+            _ => false,
         })
     }
 
     fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection {
-                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, ..
-                } => offset == index,
-                &Projection {
-                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, ..
-                } => size - offset == index,
-                _ => false
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
+                *offset == index
             }
+            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
+                size - offset == index
+            }
+            _ => false,
         })
     }
 
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection { elem: ProjectionElem::Deref, .. } => true,
-                _ => false
-            }
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
+            *e == ProjectionElem::Deref
         })
     }
 
     fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
-            match p {
-                &Projection {
-                    elem: ProjectionElem::Downcast(_, idx), ..
-                } => idx == variant,
-                _ => false
-            }
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+            ProjectionElem::Downcast(_, idx) => *idx == variant,
+            _ => false
         })
     }
 
@@ -465,7 +452,7 @@
         assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
 
         let assign = Statement {
-            kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())),
+            kind: StatementKind::Assign(box(location.clone(), Rvalue::Use(value.clone()))),
             source_info: terminator.source_info
         };
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index d873311..0ce2db9 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -107,10 +107,7 @@
         if place.base == PlaceBase::Local(self_arg()) {
             replace_base(place, Place {
                 base: PlaceBase::Local(self_arg()),
-                projection: Some(Box::new(Projection {
-                    base: None,
-                    elem: ProjectionElem::Deref,
-                })),
+                projection: Box::new([ProjectionElem::Deref]),
             });
         } else {
             self.super_place(place, context, location);
@@ -137,10 +134,7 @@
         if place.base == PlaceBase::Local(self_arg()) {
             replace_base(place, Place {
                 base: PlaceBase::Local(self_arg()),
-                projection: Some(Box::new(Projection {
-                    base: None,
-                    elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
-                })),
+                projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
             });
         } else {
             self.super_place(place, context, location);
@@ -149,13 +143,12 @@
 }
 
 fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
-    let mut projection = &mut place.projection;
-    while let Some(box proj) = projection {
-        projection = &mut proj.base;
-    }
-
     place.base = new_base.base;
-    *projection = new_base.projection;
+
+    let mut new_projection = new_base.projection.to_vec();
+    new_projection.append(&mut place.projection.to_vec());
+
+    place.projection = new_projection.into_boxed_slice();
 }
 
 fn self_arg() -> Local {
@@ -210,13 +203,12 @@
     fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
         let self_place = Place::from(self_arg());
         let base = self_place.downcast_unnamed(variant_index);
-        let field = Projection {
-            base: base.projection,
-            elem: ProjectionElem::Field(Field::new(idx), ty),
-        };
+        let mut projection = base.projection.to_vec();
+        projection.push(ProjectionElem::Field(Field::new(idx), ty));
+
         Place {
             base: base.base,
-            projection: Some(Box::new(field)),
+            projection: projection.into_boxed_slice(),
         }
     }
 
@@ -225,7 +217,10 @@
         let self_place = Place::from(self_arg());
         Statement {
             source_info,
-            kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc },
+            kind: StatementKind::SetDiscriminant {
+                place: box self_place,
+                variant_index: state_disc,
+            },
         }
     }
 
@@ -238,7 +233,7 @@
         let self_place = Place::from(self_arg());
         let assign = Statement {
             source_info: source_info(body),
-            kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)),
+            kind: StatementKind::Assign(box(temp.clone(), Rvalue::Discriminant(self_place))),
         };
         (assign, temp)
     }
@@ -296,8 +291,12 @@
             // We must assign the value first in case it gets declared dead below
             data.statements.push(Statement {
                 source_info,
-                kind: StatementKind::Assign(Place::RETURN_PLACE,
-                                            box self.make_state(state_idx, v)),
+                kind: StatementKind::Assign(
+                    box(
+                        Place::return_place(),
+                        self.make_state(state_idx, v)
+                    )
+                ),
             });
             let state = if let Some(resume) = resume { // Yield
                 let state = 3 + self.suspension_points.len();
@@ -848,7 +847,7 @@
                 kind: TerminatorKind::Drop {
                     location: Place {
                         base: PlaceBase::Local(local),
-                        projection: None,
+                        projection: box [],
                     },
                     target,
                     unwind
@@ -937,7 +936,7 @@
         // Alias tracking must know we changed the type
         body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
             source_info,
-            kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())),
+            kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())),
         })
     }
 
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index f31303c..5ad026d 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -425,22 +425,20 @@
                 // writes to `i`. To prevent this we need to create a temporary
                 // borrow of the place and pass the destination as `*temp` instead.
                 fn dest_needs_borrow(place: &Place<'_>) -> bool {
-                    place.iterate(|place_base, place_projection| {
-                        for proj in place_projection {
-                            match proj.elem {
-                                ProjectionElem::Deref |
-                                ProjectionElem::Index(_) => return true,
-                                _ => {}
-                            }
+                    for elem in place.projection.iter() {
+                        match elem {
+                            ProjectionElem::Deref |
+                            ProjectionElem::Index(_) => return true,
+                            _ => {}
                         }
+                    }
 
-                        match place_base {
-                            // Static variables need a borrow because the callee
-                            // might modify the same static.
-                            PlaceBase::Static(_) => true,
-                            _ => false
-                        }
-                    })
+                    match place.base {
+                        // Static variables need a borrow because the callee
+                        // might modify the same static.
+                        PlaceBase::Static(_) => true,
+                        _ => false
+                    }
                 }
 
                 let dest = if dest_needs_borrow(&destination.0) {
@@ -459,7 +457,7 @@
 
                     let stmt = Statement {
                         source_info: callsite.location,
-                        kind: StatementKind::Assign(tmp.clone(), box dest)
+                        kind: StatementKind::Assign(box(tmp.clone(), dest))
                     };
                     caller_body[callsite.bb]
                         .statements.push(stmt);
@@ -591,7 +589,7 @@
 
         if let Operand::Move(Place {
             base: PlaceBase::Local(local),
-            projection: None,
+            projection: box [],
         }) = arg {
             if caller_body.local_kind(local) == LocalKind::Temp {
                 // Reuse the operand if it's a temporary already
@@ -610,7 +608,7 @@
 
         let stmt = Statement {
             source_info: callsite.location,
-            kind: StatementKind::Assign(Place::from(arg_tmp), box arg),
+            kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)),
         };
         caller_body[callsite.bb].statements.push(stmt);
         arg_tmp
@@ -660,7 +658,7 @@
             match self.destination {
                 Place {
                     base: PlaceBase::Local(l),
-                    projection: None,
+                    projection: box [],
                 } => {
                     *local = l;
                     return;
@@ -684,7 +682,7 @@
         match place {
             Place {
                 base: PlaceBase::Local(RETURN_PLACE),
-                projection: None,
+                projection: box [],
             } => {
                 // Return pointer; update the place itself
                 *place = self.destination.clone();
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index abe4160..0e04e63 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -43,12 +43,21 @@
             let new_place = match *rvalue {
                 Rvalue::Ref(_, _, Place {
                     ref mut base,
-                    projection: Some(ref mut projection),
-                }) => Place {
-                    // Replace with dummy
-                    base: mem::replace(base, PlaceBase::Local(Local::new(0))),
-                    projection: projection.base.take(),
-                },
+                    projection: ref mut projection @ box [.., _],
+                }) => {
+                    if let box [proj_l @ .., proj_r] = projection {
+                        let place = Place {
+                            // Replace with dummy
+                            base: mem::replace(base, PlaceBase::Local(Local::new(0))),
+                            projection: proj_l.to_vec().into_boxed_slice(),
+                        };
+                        *projection = vec![proj_r.clone()].into_boxed_slice();
+
+                        place
+                    } else {
+                        unreachable!();
+                    }
+                }
                 _ => bug!("Detected `&*` but didn't find `&*`!"),
             };
             *rvalue = Rvalue::Use(Operand::Copy(new_place))
@@ -83,13 +92,11 @@
 impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         if let Rvalue::Ref(_, _, Place {
-            ref base,
-            projection: Some(ref projection),
-        }) = *rvalue {
-            if let ProjectionElem::Deref = projection.elem {
-                if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() {
-                    self.optimizations.and_stars.insert(location);
-                }
+            base,
+            projection: box [proj_base @ .., ProjectionElem::Deref],
+        }) = rvalue {
+            if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
+                self.optimizations.and_stars.insert(location);
             }
         }
 
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index cdccdfe..7d1b96b 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -187,7 +187,7 @@
                 span,
                 scope: OUTERMOST_SOURCE_SCOPE
             },
-            kind: StatementKind::Assign(Place::from(dest), box rvalue)
+            kind: StatementKind::Assign(box(Place::from(dest), rvalue))
         });
     }
 
@@ -222,10 +222,10 @@
         // First, take the Rvalue or Call out of the source MIR,
         // or duplicate it, depending on keep_original.
         if loc.statement_index < no_stmts {
-            let (rvalue, source_info) = {
+            let (mut rvalue, source_info) = {
                 let statement = &mut self.source[loc.block].statements[loc.statement_index];
                 let rhs = match statement.kind {
-                    StatementKind::Assign(_, ref mut rhs) => rhs,
+                    StatementKind::Assign(box(_, ref mut rhs)) => rhs,
                     _ => {
                         span_bug!(statement.source_info.span, "{:?} is not an assignment",
                                   statement);
@@ -235,12 +235,11 @@
                 (if self.keep_original {
                     rhs.clone()
                 } else {
-                    let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
+                    let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
                     mem::replace(rhs, unit)
                 }, statement.source_info)
             };
 
-            let mut rvalue = *rvalue;
             self.visit_rvalue(&mut rvalue, loc);
             self.assign(new_temp, rvalue, source_info.span);
         } else {
@@ -318,7 +317,7 @@
                         ty,
                         def_id,
                     }),
-                    projection: None,
+                    projection: box [],
                 }
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
@@ -326,7 +325,7 @@
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
+                        StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
                             // Use the underlying local for this (necessarily interior) borrow.
                             let ty = place.base.ty(local_decls).ty;
                             let span = statement.source_info.span;
@@ -334,9 +333,9 @@
                             Operand::Move(Place {
                                 base: mem::replace(
                                     &mut place.base,
-                                    promoted_place(ty, span).base
+                                    promoted_place(ty, span).base,
                                 ),
-                                projection: None,
+                                projection: box [],
                             })
                         }
                         _ => bug!()
@@ -345,7 +344,7 @@
                 Candidate::Repeat(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
+                        StatementKind::Assign(box(_, Rvalue::Repeat(ref mut operand, _))) => {
                             let ty = operand.ty(local_decls, self.tcx);
                             let span = statement.source_info.span;
                             mem::replace(
@@ -420,10 +419,10 @@
             Candidate::Repeat(Location { block, statement_index }) |
             Candidate::Ref(Location { block, statement_index }) => {
                 match body[block].statements[statement_index].kind {
-                    StatementKind::Assign(Place {
+                    StatementKind::Assign(box(Place {
                         base: PlaceBase::Local(local),
-                        projection: None,
-                    }, _) => {
+                        projection: box [],
+                    }, _)) => {
                         if temps[local] == TempState::PromotedOut {
                             // Already promoted.
                             continue;
@@ -473,10 +472,10 @@
     for block in body.basic_blocks_mut() {
         block.statements.retain(|statement| {
             match statement.kind {
-                StatementKind::Assign(Place {
+                StatementKind::Assign(box(Place {
                     base: PlaceBase::Local(index),
-                    projection: None,
-                }, _) |
+                    projection: box [],
+                }, _)) |
                 StatementKind::StorageLive(index) |
                 StatementKind::StorageDead(index) => {
                     !promoted(index)
@@ -488,7 +487,7 @@
         match terminator.kind {
             TerminatorKind::Drop { location: Place {
                 base: PlaceBase::Local(index),
-                projection: None,
+                projection: box [],
             }, target, .. } => {
                 if promoted(index) {
                     terminator.kind = TerminatorKind::Goto {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index a77421c..7cc1e63 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -25,11 +25,13 @@
 use syntax::symbol::sym;
 use syntax_pos::{Span, DUMMY_SP};
 
+use std::borrow::Cow;
 use std::cell::Cell;
 use std::fmt;
 use std::ops::{Deref, Index, IndexMut};
 use std::usize;
 
+use rustc::hir::HirId;
 use crate::transform::{MirPass, MirSource};
 use super::promote_consts::{self, Candidate, TempState};
 
@@ -185,26 +187,28 @@
         cx: &ConstCx<'_, 'tcx>,
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
-        let proj = place.projection.as_ref().unwrap();
+        if let [proj_base @ .., elem] = place.projection {
+            let base_qualif = Self::in_place(cx, PlaceRef {
+                base: place.base,
+                projection: proj_base,
+            });
+            let qualif = base_qualif && Self::mask_for_ty(
+                cx,
+                Place::ty_from(place.base, proj_base, cx.body, cx.tcx)
+                    .projection_ty(cx.tcx, elem)
+                    .ty,
+            );
+            match elem {
+                ProjectionElem::Deref |
+                ProjectionElem::Subslice { .. } |
+                ProjectionElem::Field(..) |
+                ProjectionElem::ConstantIndex { .. } |
+                ProjectionElem::Downcast(..) => qualif,
 
-        let base_qualif = Self::in_place(cx, PlaceRef {
-            base: place.base,
-            projection: &proj.base,
-        });
-        let qualif = base_qualif && Self::mask_for_ty(
-            cx,
-            Place::ty_from(place.base, &proj.base, cx.body, cx.tcx)
-                .projection_ty(cx.tcx, &proj.elem)
-                .ty,
-        );
-        match proj.elem {
-            ProjectionElem::Deref |
-            ProjectionElem::Subslice { .. } |
-            ProjectionElem::Field(..) |
-            ProjectionElem::ConstantIndex { .. } |
-            ProjectionElem::Downcast(..) => qualif,
-
-            ProjectionElem::Index(local) => qualif || Self::in_local(cx, local),
+                ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local),
+            }
+        } else {
+            bug!("This should be called if projection is not empty");
         }
     }
 
@@ -219,24 +223,24 @@
         match place {
             PlaceRef {
                 base: PlaceBase::Local(local),
-                projection: None,
+                projection: [],
             } => Self::in_local(cx, *local),
             PlaceRef {
                 base: PlaceBase::Static(box Static {
                     kind: StaticKind::Promoted(..),
                     ..
                 }),
-                projection: None,
+                projection: [],
             } => bug!("qualifying already promoted MIR"),
             PlaceRef {
                 base: PlaceBase::Static(static_),
-                projection: None,
+                projection: [],
             } => {
                 Self::in_static(cx, static_)
             },
             PlaceRef {
                 base: _,
-                projection: Some(_),
+                projection: [.., _],
             } => Self::in_projection(cx, place),
         }
     }
@@ -287,13 +291,13 @@
 
             Rvalue::Ref(_, _, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
-                if let Some(ref proj) = place.projection {
-                    if let ProjectionElem::Deref = proj.elem {
-                        let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty;
+                if let box [proj_base @ .., elem] = &place.projection {
+                    if ProjectionElem::Deref == *elem {
+                        let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
                         if let ty::Ref(..) = base_ty.sty {
                             return Self::in_place(cx, PlaceRef {
                                 base: &place.base,
-                                projection: &proj.base,
+                                projection: proj_base,
                             });
                         }
                     }
@@ -451,30 +455,32 @@
         cx: &ConstCx<'_, 'tcx>,
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
-        let proj = place.projection.as_ref().unwrap();
+        if let [proj_base @ .., elem] = place.projection {
+            match elem {
+                ProjectionElem::Deref |
+                ProjectionElem::Downcast(..) => return true,
 
-        match proj.elem {
-            ProjectionElem::Deref |
-            ProjectionElem::Downcast(..) => return true,
+                ProjectionElem::ConstantIndex {..} |
+                ProjectionElem::Subslice {..} |
+                ProjectionElem::Index(_) => {}
 
-            ProjectionElem::ConstantIndex {..} |
-            ProjectionElem::Subslice {..} |
-            ProjectionElem::Index(_) => {}
-
-            ProjectionElem::Field(..) => {
-                if cx.mode == Mode::NonConstFn {
-                    let base_ty = Place::ty_from(place.base, &proj.base, cx.body, cx.tcx).ty;
-                    if let Some(def) = base_ty.ty_adt_def() {
-                        // No promotion of union field accesses.
-                        if def.is_union() {
-                            return true;
+                ProjectionElem::Field(..) => {
+                    if cx.mode == Mode::NonConstFn {
+                        let base_ty = Place::ty_from(place.base, proj_base, cx.body, cx.tcx).ty;
+                        if let Some(def) = base_ty.ty_adt_def() {
+                            // No promotion of union field accesses.
+                            if def.is_union() {
+                                return true;
+                            }
                         }
                     }
                 }
             }
-        }
 
-        Self::in_projection_structurally(cx, place)
+            Self::in_projection_structurally(cx, place)
+        } else {
+            bug!("This should be called if projection is not empty");
+        }
     }
 
     fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
@@ -804,23 +810,18 @@
                     // We might have a candidate for promotion.
                     let candidate = Candidate::Ref(location);
                     // Start by traversing to the "base", with non-deref projections removed.
-                    let mut place_projection = &place.projection;
-                    while let Some(proj) = place_projection {
-                        if proj.elem == ProjectionElem::Deref {
-                            break;
-                        }
-                        place_projection = &proj.base;
-                    }
+                    let deref_proj =
+                        place.projection.iter().rev().find(|&elem| *elem == ProjectionElem::Deref);
 
                     debug!(
                         "qualify_consts: promotion candidate: place={:?} {:?}",
-                        place.base, place_projection
+                        place.base, deref_proj
                     );
                     // We can only promote interior borrows of promotable temps (non-temps
                     // don't get promoted anyway).
                     // (If we bailed out of the loop due to a `Deref` above, we will definitely
                     // not enter the conditional here.)
-                    if let (PlaceBase::Local(local), None) = (&place.base, place_projection) {
+                    if let (PlaceBase::Local(local), None) = (&place.base, deref_proj) {
                         if self.body.local_kind(*local) == LocalKind::Temp {
                             debug!("qualify_consts: promotion candidate: local={:?}", local);
                             // The borrowed place doesn't have `HasMutInterior`
@@ -856,27 +857,27 @@
             _ => {},
         }
 
-        let mut dest_projection = &dest.projection;
+        let mut dest_projection = &dest.projection[..];
         let index = loop {
             match (&dest.base, dest_projection) {
                 // We treat all locals equal in constants
-                (&PlaceBase::Local(index), None) => break index,
+                (&PlaceBase::Local(index), []) => break index,
                 // projections are transparent for assignments
                 // we qualify the entire destination at once, even if just a field would have
                 // stricter qualification
-                (base, Some(proj)) => {
+                (base, [proj_base @ .., _]) => {
                     // Catch more errors in the destination. `visit_place` also checks various
                     // projection rules like union field access and raw pointer deref
                     let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
                     self.visit_place_base(base, context, location);
-                    self.visit_projection(base, proj, context, location);
-                    dest_projection = &proj.base;
+                    self.visit_projection(base, dest_projection, context, location);
+                    dest_projection = proj_base;
                 },
                 (&PlaceBase::Static(box Static {
                     kind: StaticKind::Promoted(..),
                     ..
-                }), None) => bug!("promoteds don't exist yet during promotion"),
-                (&PlaceBase::Static(box Static{ kind: _, .. }), None) => {
+                }), []) => bug!("promoteds don't exist yet during promotion"),
+                (&PlaceBase::Static(box Static{ kind: _, .. }), []) => {
                     // Catch more errors in the destination. `visit_place` also checks that we
                     // do not try to access statics from constants or try to mutate statics
                     let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
@@ -981,23 +982,25 @@
         for candidate in &self.promotion_candidates {
             match *candidate {
                 Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
-                    if let StatementKind::Assign(_, box Rvalue::Repeat(
+                    if let StatementKind::Assign(box(_, Rvalue::Repeat(
                         Operand::Move(Place {
                             base: PlaceBase::Local(index),
-                            projection: None,
+                            projection: box [],
                         }),
                         _
-                    )) = self.body[bb].statements[stmt_idx].kind {
+                    ))) = self.body[bb].statements[stmt_idx].kind {
                         promoted_temps.insert(index);
                     }
                 }
                 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
                     if let StatementKind::Assign(
-                        _,
-                        box Rvalue::Ref(_, _, Place {
-                            base: PlaceBase::Local(index),
-                            projection: None,
-                        })
+                        box(
+                            _,
+                            Rvalue::Ref(_, _, Place {
+                                base: PlaceBase::Local(index),
+                                projection: box [],
+                            })
+                        )
                     ) = self.body[bb].statements[stmt_idx].kind {
                         promoted_temps.insert(index);
                     }
@@ -1082,7 +1085,7 @@
     fn visit_projection(
         &mut self,
         place_base: &PlaceBase<'tcx>,
-        proj: &Projection<'tcx>,
+        proj: &[PlaceElem<'tcx>],
         context: PlaceContext,
         location: Location,
     ) {
@@ -1091,62 +1094,65 @@
             proj, context, location,
         );
         self.super_projection(place_base, proj, context, location);
-        match proj.elem {
-            ProjectionElem::Deref => {
-                if context.is_mutating_use() {
-                    // `not_const` errors out in const contexts
-                    self.not_const()
-                }
-                let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
-                match self.mode {
-                    Mode::NonConstFn => {},
-                    _ => {
-                        if let ty::RawPtr(_) = base_ty.sty {
-                            if !self.tcx.features().const_raw_ptr_deref {
-                                emit_feature_err(
-                                    &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
-                                    self.span, GateIssue::Language,
-                                    &format!(
-                                        "dereferencing raw pointers in {}s is unstable",
-                                        self.mode,
-                                    ),
-                                );
+
+        if let [proj_base @ .., elem] = proj {
+            match elem {
+                ProjectionElem::Deref => {
+                    if context.is_mutating_use() {
+                        // `not_const` errors out in const contexts
+                        self.not_const()
+                    }
+                    let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
+                    match self.mode {
+                        Mode::NonConstFn => {},
+                        _ => {
+                            if let ty::RawPtr(_) = base_ty.sty {
+                                if !self.tcx.features().const_raw_ptr_deref {
+                                    emit_feature_err(
+                                        &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
+                                        self.span, GateIssue::Language,
+                                        &format!(
+                                            "dereferencing raw pointers in {}s is unstable",
+                                            self.mode,
+                                        ),
+                                    );
+                                }
                             }
                         }
                     }
                 }
-            }
 
-            ProjectionElem::ConstantIndex {..} |
-            ProjectionElem::Subslice {..} |
-            ProjectionElem::Field(..) |
-            ProjectionElem::Index(_) => {
-                let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
-                if let Some(def) = base_ty.ty_adt_def() {
-                    if def.is_union() {
-                        match self.mode {
-                            Mode::ConstFn => {
-                                if !self.tcx.features().const_fn_union {
-                                    emit_feature_err(
-                                        &self.tcx.sess.parse_sess, sym::const_fn_union,
-                                        self.span, GateIssue::Language,
-                                        "unions in const fn are unstable",
-                                    );
-                                }
-                            },
+                ProjectionElem::ConstantIndex {..} |
+                ProjectionElem::Subslice {..} |
+                ProjectionElem::Field(..) |
+                ProjectionElem::Index(_) => {
+                    let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
+                    if let Some(def) = base_ty.ty_adt_def() {
+                        if def.is_union() {
+                            match self.mode {
+                                Mode::ConstFn => {
+                                    if !self.tcx.features().const_fn_union {
+                                        emit_feature_err(
+                                            &self.tcx.sess.parse_sess, sym::const_fn_union,
+                                            self.span, GateIssue::Language,
+                                            "unions in const fn are unstable",
+                                        );
+                                    }
+                                },
 
-                            | Mode::NonConstFn
-                            | Mode::Static
-                            | Mode::StaticMut
-                            | Mode::Const
-                            => {},
+                                | Mode::NonConstFn
+                                | Mode::Static
+                                | Mode::StaticMut
+                                | Mode::Const
+                                => {},
+                            }
                         }
                     }
                 }
-            }
 
-            ProjectionElem::Downcast(..) => {
-                self.not_const()
+                ProjectionElem::Downcast(..) => {
+                    self.not_const()
+                }
             }
         }
     }
@@ -1160,7 +1166,7 @@
                 // Mark the consumed locals to indicate later drops are noops.
                 if let Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } = *place {
                     self.cx.per_local[NeedsDrop].remove(local);
                 }
@@ -1177,11 +1183,11 @@
         if let Rvalue::Ref(_, kind, ref place) = *rvalue {
             // Special-case reborrows.
             let mut reborrow_place = None;
-            if let Some(ref proj) = place.projection {
-                if let ProjectionElem::Deref = proj.elem {
-                    let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
+            if let box [proj_base @ .., elem] = &place.projection {
+                if *elem == ProjectionElem::Deref {
+                    let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.sty {
-                        reborrow_place = Some(&proj.base);
+                        reborrow_place = Some(proj_base);
                     }
                 }
             }
@@ -1202,9 +1208,7 @@
                     ),
                 };
                 self.visit_place_base(&place.base, ctx, location);
-                if let Some(proj) = proj {
-                    self.visit_projection(&place.base, proj, ctx, location);
-                }
+                self.visit_projection(&place.base, proj, ctx, location);
             } else {
                 self.super_rvalue(rvalue, location);
             }
@@ -1475,7 +1479,7 @@
                 // conservatively, that drop elaboration will do.
                 let needs_drop = if let Place {
                     base: PlaceBase::Local(local),
-                    projection: None,
+                    projection: box [],
                 } = *place {
                     if NeedsDrop::in_local(self, local) {
                         Some(self.body.local_decls[local].source_info.span)
@@ -1596,51 +1600,24 @@
         }
 
         let def_id = src.def_id();
-        let id = tcx.hir().as_local_hir_id(def_id).unwrap();
-        let mut const_promoted_temps = None;
-        let mode = match tcx.hir().body_owner_kind(id) {
-            hir::BodyOwnerKind::Closure => Mode::NonConstFn,
-            hir::BodyOwnerKind::Fn => {
-                if tcx.is_const_fn(def_id) {
-                    Mode::ConstFn
-                } else {
-                    Mode::NonConstFn
-                }
-            }
-            hir::BodyOwnerKind::Const => {
-                const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1);
-                Mode::Const
-            }
-            hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static,
-            hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
-        };
+        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+
+        let mode = determine_mode(tcx, hir_id, def_id);
 
         debug!("run_pass: mode={:?}", mode);
-        if mode == Mode::NonConstFn || mode == Mode::ConstFn {
+        if let Mode::NonConstFn | Mode::ConstFn = mode {
             // This is ugly because Checker holds onto mir,
             // which can't be mutated until its scope ends.
             let (temps, candidates) = {
                 let mut checker = Checker::new(tcx, def_id, body, mode);
-                if mode == Mode::ConstFn {
+                if let Mode::ConstFn = mode {
                     if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
                         checker.check_const();
                     } else if tcx.is_min_const_fn(def_id) {
-                        // enforce `min_const_fn` for stable const fns
+                        // Enforce `min_const_fn` for stable `const fn`s.
                         use super::qualify_min_const_fn::is_min_const_fn;
                         if let Err((span, err)) = is_min_const_fn(tcx, def_id, body) {
-                            let mut diag = struct_span_err!(
-                                tcx.sess,
-                                span,
-                                E0723,
-                                "{}",
-                                err,
-                            );
-                            diag.note("for more information, see issue \
-                                       https://github.com/rust-lang/rust/issues/57563");
-                            diag.help(
-                                "add `#![feature(const_fn)]` to the crate attributes to enable",
-                            );
-                            diag.emit();
+                            error_min_const_fn_violation(tcx, span, err);
                         } else {
                             // this should not produce any errors, but better safe than sorry
                             // FIXME(#53819)
@@ -1664,107 +1641,119 @@
                 promote_consts::promote_candidates(def_id, body, tcx, temps, candidates)
             );
         } else {
-            if !body.control_flow_destroyed.is_empty() {
-                let mut locals = body.vars_iter();
-                if let Some(local) = locals.next() {
-                    let span = body.local_decls[local].source_info.span;
-                    let mut error = tcx.sess.struct_span_err(
-                        span,
-                        &format!(
-                            "new features like let bindings are not permitted in {}s \
-                            which also use short circuiting operators",
-                            mode,
-                        ),
-                    );
-                    for (span, kind) in body.control_flow_destroyed.iter() {
-                        error.span_note(
-                            *span,
-                            &format!("use of {} here does not actually short circuit due to \
-                            the const evaluator presently not being able to do control flow. \
-                            See https://github.com/rust-lang/rust/issues/49146 for more \
-                            information.", kind),
-                        );
-                    }
-                    for local in locals {
-                        let span = body.local_decls[local].source_info.span;
-                        error.span_note(
-                            span,
-                            "more locals defined here",
-                        );
-                    }
-                    error.emit();
-                }
-            }
-            let promoted_temps = if mode == Mode::Const {
-                // Already computed by `mir_const_qualif`.
-                const_promoted_temps.unwrap()
-            } else {
-                Checker::new(tcx, def_id, body, mode).check_const().1
-            };
+            check_short_circuiting_in_const_local(tcx, body, mode);
 
-            // In `const` and `static` everything without `StorageDead`
-            // is `'static`, we don't have to create promoted MIR fragments,
-            // just remove `Drop` and `StorageDead` on "promoted" locals.
-            debug!("run_pass: promoted_temps={:?}", promoted_temps);
-            for block in body.basic_blocks_mut() {
-                block.statements.retain(|statement| {
-                    match statement.kind {
-                        StatementKind::StorageDead(index) => {
-                            !promoted_temps.contains(index)
-                        }
-                        _ => true
-                    }
-                });
-                let terminator = block.terminator_mut();
-                match terminator.kind {
-                    TerminatorKind::Drop {
-                        location: Place {
-                            base: PlaceBase::Local(index),
-                            projection: None,
-                        },
-                        target,
-                        ..
-                    } => {
-                        if promoted_temps.contains(index) {
-                            terminator.kind = TerminatorKind::Goto {
-                                target,
-                            };
-                        }
-                    }
-                    _ => {}
-                }
-            }
+            let promoted_temps = match mode {
+                Mode::Const => tcx.mir_const_qualif(def_id).1,
+                _ => Checker::new(tcx, def_id, body, mode).check_const().1,
+            };
+            remove_drop_and_storage_dead_on_promoted_locals(body, promoted_temps);
         }
 
-        // Statics must be Sync.
-        if mode == Mode::Static {
-            // `#[thread_local]` statics don't have to be `Sync`.
-            for attr in &tcx.get_attrs(def_id)[..] {
-                if attr.check_name(sym::thread_local) {
-                    return;
-                }
-            }
-            let ty = body.return_ty();
-            tcx.infer_ctxt().enter(|infcx| {
-                let param_env = ty::ParamEnv::empty();
-                let cause = traits::ObligationCause::new(body.span, id, traits::SharedStatic);
-                let mut fulfillment_cx = traits::FulfillmentContext::new();
-                fulfillment_cx.register_bound(&infcx,
-                                              param_env,
-                                              ty,
-                                              tcx.require_lang_item(
-                                                  lang_items::SyncTraitLangItem,
-                                                  Some(body.span)
-                                              ),
-                                              cause);
-                if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
-                    infcx.report_fulfillment_errors(&err, None, false);
-                }
-            });
+        if mode == Mode::Static && !tcx.has_attr(def_id, sym::thread_local) {
+            // `static`s (not `static mut`s) which are not `#[thread_local]` must be `Sync`.
+            check_static_is_sync(tcx, body, hir_id);
         }
     }
 }
 
+fn determine_mode(tcx: TyCtxt<'_>, hir_id: HirId, def_id: DefId) -> Mode {
+    match tcx.hir().body_owner_kind(hir_id) {
+        hir::BodyOwnerKind::Closure => Mode::NonConstFn,
+        hir::BodyOwnerKind::Fn if tcx.is_const_fn(def_id) => Mode::ConstFn,
+        hir::BodyOwnerKind::Fn => Mode::NonConstFn,
+        hir::BodyOwnerKind::Const => Mode::Const,
+        hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static,
+        hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
+    }
+}
+
+fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) {
+    struct_span_err!(tcx.sess, span, E0723, "{}", msg)
+        .note("for more information, see issue https://github.com/rust-lang/rust/issues/57563")
+        .help("add `#![feature(const_fn)]` to the crate attributes to enable")
+        .emit();
+}
+
+fn check_short_circuiting_in_const_local(tcx: TyCtxt<'_>, body: &mut Body<'tcx>, mode: Mode) {
+    if body.control_flow_destroyed.is_empty() {
+        return;
+    }
+
+    let mut locals = body.vars_iter();
+    if let Some(local) = locals.next() {
+        let span = body.local_decls[local].source_info.span;
+        let mut error = tcx.sess.struct_span_err(
+            span,
+            &format!(
+                "new features like let bindings are not permitted in {}s \
+                which also use short circuiting operators",
+                mode,
+            ),
+        );
+        for (span, kind) in body.control_flow_destroyed.iter() {
+            error.span_note(
+                *span,
+                &format!("use of {} here does not actually short circuit due to \
+                the const evaluator presently not being able to do control flow. \
+                See https://github.com/rust-lang/rust/issues/49146 for more \
+                information.", kind),
+            );
+        }
+        for local in locals {
+            let span = body.local_decls[local].source_info.span;
+            error.span_note(span, "more locals defined here");
+        }
+        error.emit();
+    }
+}
+
+/// In `const` and `static` everything without `StorageDead`
+/// is `'static`, we don't have to create promoted MIR fragments,
+/// just remove `Drop` and `StorageDead` on "promoted" locals.
+fn remove_drop_and_storage_dead_on_promoted_locals(
+    body: &mut Body<'tcx>,
+    promoted_temps: &BitSet<Local>,
+) {
+    debug!("run_pass: promoted_temps={:?}", promoted_temps);
+
+    for block in body.basic_blocks_mut() {
+        block.statements.retain(|statement| {
+            match statement.kind {
+                StatementKind::StorageDead(index) => !promoted_temps.contains(index),
+                _ => true
+            }
+        });
+        let terminator = block.terminator_mut();
+        match terminator.kind {
+            TerminatorKind::Drop {
+                location: Place {
+                    base: PlaceBase::Local(index),
+                    projection: box [],
+                },
+                target,
+                ..
+            } if promoted_temps.contains(index) => {
+                terminator.kind = TerminatorKind::Goto { target };
+            }
+            _ => {}
+        }
+    }
+}
+
+fn check_static_is_sync(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, hir_id: HirId) {
+    let ty = body.return_ty();
+    tcx.infer_ctxt().enter(|infcx| {
+        let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic);
+        let mut fulfillment_cx = traits::FulfillmentContext::new();
+        let sync_def_id = tcx.require_lang_item(lang_items::SyncTraitLangItem, Some(body.span));
+        fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
+        if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
+            infcx.report_fulfillment_errors(&err, None, false);
+        }
+    });
+}
+
 fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<FxHashSet<usize>> {
     let attrs = tcx.get_attrs(def_id);
     let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 5609352..80e020a 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -206,7 +206,7 @@
 ) -> McfResult {
     let span = statement.source_info.span;
     match &statement.kind {
-        StatementKind::Assign(place, rval) => {
+        StatementKind::Assign(box(place, rval)) => {
             check_place(place, span)?;
             check_rvalue(tcx, body, rval, span)
         }
@@ -249,28 +249,26 @@
     place: &Place<'tcx>,
     span: Span,
 ) -> McfResult {
-    place.iterate(|place_base, place_projection| {
-        for proj in place_projection {
-            match proj.elem {
-                ProjectionElem::Downcast(..) => {
-                    return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
-                }
-                ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Subslice { .. }
-                | ProjectionElem::Deref
-                | ProjectionElem::Field(..)
-                | ProjectionElem::Index(_) => {}
+    for elem in place.projection.iter() {
+        match elem {
+            ProjectionElem::Downcast(..) => {
+                return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
             }
+            ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Subslice { .. }
+            | ProjectionElem::Deref
+            | ProjectionElem::Field(..)
+            | ProjectionElem::Index(_) => {}
         }
+    }
 
-        match place_base {
-            PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
-                Err((span, "cannot access `static` items in const fn".into()))
-            }
-            PlaceBase::Local(_)
-            | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
+    match place.base {
+        PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
+            Err((span, "cannot access `static` items in const fn".into()))
         }
-    })
+        PlaceBase::Local(_)
+        | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
+    }
 }
 
 fn check_terminator(
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index 73089a2..70b1194 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -41,10 +41,10 @@
                     // These are all nops in a landing pad
                 }
 
-                StatementKind::Assign(Place {
+                StatementKind::Assign(box(Place {
                     base: PlaceBase::Local(_),
-                    projection: None,
-                }, box Rvalue::Use(_)) => {
+                    projection: box [],
+                }, Rvalue::Use(_))) => {
                     // Writing to a local (e.g., a drop flag) does not
                     // turn a landing pad to a non-nop
                 }
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 1d3bf24..68fa082 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -120,11 +120,11 @@
     let peek_arg_place = match args[0] {
         mir::Operand::Copy(ref place @ mir::Place {
             base: mir::PlaceBase::Local(_),
-            projection: None,
+            projection: box [],
         }) |
         mir::Operand::Move(ref place @ mir::Place {
             base: mir::PlaceBase::Local(_),
-            projection: None,
+            projection: box [],
         }) => Some(place),
         _ => None,
     };
@@ -150,7 +150,7 @@
     for (j, stmt) in statements.iter().enumerate() {
         debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
         let (place, rvalue) = match stmt.kind {
-            mir::StatementKind::Assign(ref place, ref rvalue) => {
+            mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
                 (place, rvalue)
             }
             mir::StatementKind::FakeRead(..) |
@@ -166,7 +166,7 @@
         };
 
         if place == peek_arg_place {
-            if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue {
+            if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = *rvalue {
                 // Okay, our search is over.
                 match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
                     LookupResult::Exact(peek_mpi) => {
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index 8199a25..34ad5cb 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -61,14 +61,14 @@
                     rvalue: &Rvalue<'tcx>,
                     location: Location) {
         if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
-            if let Some(ref proj) = src_place.projection {
+            if let box [proj_base @ .., elem] = &src_place.projection {
                 if let ProjectionElem::ConstantIndex{offset: _,
                                                      min_length: _,
-                                                     from_end: false} = proj.elem {
+                                                     from_end: false} = elem {
                     // no need to transformation
                 } else {
                     let place_ty =
-                        Place::ty_from(&src_place.base, &proj.base, self.body, self.tcx).ty;
+                        Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty;
                     if let ty::Array(item_ty, const_size) = place_ty.sty {
                         if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
                             assert!(size <= u32::max_value() as u64,
@@ -78,7 +78,7 @@
                                 location,
                                 dst_place,
                                 &src_place.base,
-                                proj,
+                                &src_place.projection,
                                 item_ty,
                                 size as u32,
                             );
@@ -97,73 +97,76 @@
                location: Location,
                dst_place: &Place<'tcx>,
                base: &PlaceBase<'tcx>,
-               proj: &Projection<'tcx>,
+               proj: &[PlaceElem<'tcx>],
                item_ty: &'tcx ty::TyS<'tcx>,
                size: u32) {
-        match proj.elem {
-            // uniforms statements like_10 = move _2[:-1];
-            ProjectionElem::Subslice{from, to} => {
-                self.patch.make_nop(location);
-                let temps : Vec<_> = (from..(size-to)).map(|i| {
-                    let temp = self.patch.new_temp(item_ty, self.body.source_info(location).span);
-                    self.patch.add_statement(location, StatementKind::StorageLive(temp));
+        if let [proj_base @ .., elem] = proj {
+            match elem {
+                // uniforms statements like_10 = move _2[:-1];
+                ProjectionElem::Subslice{from, to} => {
+                    self.patch.make_nop(location);
+                    let temps : Vec<_> = (*from..(size-*to)).map(|i| {
+                        let temp =
+                            self.patch.new_temp(item_ty, self.body.source_info(location).span);
+                        self.patch.add_statement(location, StatementKind::StorageLive(temp));
+
+                        let mut projection = proj_base.to_vec();
+                        projection.push(ProjectionElem::ConstantIndex {
+                            offset: i,
+                            min_length: size,
+                            from_end: false,
+                        });
+                        self.patch.add_assign(location,
+                                              Place::from(temp),
+                                              Rvalue::Use(
+                                                  Operand::Move(
+                                                      Place {
+                                                          base: base.clone(),
+                                                          projection: projection.into_boxed_slice(),
+                                                      }
+                                                  )
+                                              )
+                        );
+                        temp
+                    }).collect();
+                    self.patch.add_assign(
+                        location,
+                        dst_place.clone(),
+                        Rvalue::Aggregate(
+                            box AggregateKind::Array(item_ty),
+                            temps.iter().map(
+                                |x| Operand::Move(Place::from(*x))
+                            ).collect()
+                        )
+                    );
+                    for temp in temps {
+                        self.patch.add_statement(location, StatementKind::StorageDead(temp));
+                    }
+                }
+                // uniforms statements like _11 = move _2[-1 of 1];
+                ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
+                    self.patch.make_nop(location);
+
+                    let mut projection = proj_base.to_vec();
+                    projection.push(ProjectionElem::ConstantIndex {
+                        offset: size - offset,
+                        min_length: size,
+                        from_end: false,
+                    });
                     self.patch.add_assign(location,
-                                          Place::from(temp),
+                                          dst_place.clone(),
                                           Rvalue::Use(
                                               Operand::Move(
                                                   Place {
                                                       base: base.clone(),
-                                                      projection: Some(box Projection {
-                                                          base: proj.base.clone(),
-                                                          elem: ProjectionElem::ConstantIndex {
-                                                              offset: i,
-                                                              min_length: size,
-                                                              from_end: false,
-                                                          }
-                                                      }),
+                                                      projection: projection.into_boxed_slice(),
                                                   }
                                               )
                                           )
                     );
-                    temp
-                }).collect();
-                self.patch.add_assign(
-                    location,
-                    dst_place.clone(),
-                    Rvalue::Aggregate(
-                        box AggregateKind::Array(item_ty),
-                        temps.iter().map(
-                            |x| Operand::Move(Place::from(*x))
-                        ).collect()
-                    )
-                );
-                for temp in temps {
-                    self.patch.add_statement(location, StatementKind::StorageDead(temp));
                 }
+                _ => {}
             }
-            // uniforms statements like _11 = move _2[-1 of 1];
-            ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
-                self.patch.make_nop(location);
-                self.patch.add_assign(location,
-                                      dst_place.clone(),
-                                      Rvalue::Use(
-                                          Operand::Move(
-                                              Place {
-                                                  base: base.clone(),
-                                                  projection: Some(box Projection {
-                                                      base: proj.base.clone(),
-                                                      elem: ProjectionElem::ConstantIndex {
-                                                          offset: size - offset,
-                                                          min_length: size,
-                                                          from_end: false,
-                                                      },
-                                                  }),
-                                              }
-                                          )
-                                      )
-                );
-            }
-            _ => {}
         }
     }
 }
@@ -197,12 +200,12 @@
 
             for candidate in &visitor.candidates {
                 let statement = &body[candidate.block].statements[candidate.statement_index];
-                if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
-                    if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval {
+                if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
+                    if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
                         let items : Vec<_> = items.iter().map(|item| {
                             if let Operand::Move(Place {
                                 base: PlaceBase::Local(local),
-                                projection: None,
+                                projection: box [],
                             }) = item {
                                 let local_use = &visitor.locals_use[*local];
                                 let opt_index_and_place =
@@ -269,16 +272,17 @@
             }
             patch.make_nop(candidate);
             let size = opt_size.unwrap() as u32;
-            patch.add_assign(candidate,
-                             dst_place.clone(),
-                             Rvalue::Use(
-                                 Operand::Move(
-                                     Place {
-                                         base: src_place.base.clone(),
-                                         projection: Some(box Projection {
-                                             base: src_place.projection.clone(),
-                                             elem: ProjectionElem::Subslice{
-                                                 from: min, to: size - max - 1}})})));
+
+            let mut projection = src_place.projection.to_vec();
+            projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 });
+            patch.add_assign(
+                candidate,
+                dst_place.clone(),
+                Rvalue::Use(Operand::Move(Place {
+                    base: src_place.base.clone(),
+                    projection: projection.into_boxed_slice(),
+                })),
+            );
         }
     }
 
@@ -289,23 +293,34 @@
             if block.statements.len() > location.statement_index {
                 let statement = &block.statements[location.statement_index];
                 if let StatementKind::Assign(
-                    Place {
-                        base: PlaceBase::Local(_),
-                        projection: None,
-                    },
-                    box Rvalue::Use(Operand::Move(Place {
-                        base,
-                        projection: Some(box Projection {
-                            base: proj_base,
-                            elem: ProjectionElem::ConstantIndex {
+                    box(
+                        Place {
+                            base: PlaceBase::Local(_),
+                            projection: box [],
+                        },
+                        Rvalue::Use(Operand::Move(Place {
+                            base: _,
+                            projection: box [.., ProjectionElem::ConstantIndex {
                                 offset, min_length: _, from_end: false
-                            }
-                        }),
-                    }))) = &statement.kind {
-                    return Some((*offset, PlaceRef {
-                        base,
-                        projection: proj_base,
-                    }))
+                            }],
+                        })),
+                    )
+                ) = &statement.kind {
+                    // FIXME remove once we can use slices patterns
+                    if let StatementKind::Assign(
+                        box(
+                            _,
+                            Rvalue::Use(Operand::Move(Place {
+                                base,
+                                projection: box [proj_base @ .., _],
+                            })),
+                        )
+                    ) = &statement.kind {
+                        return Some((*offset, PlaceRef {
+                            base,
+                            projection: proj_base,
+                        }))
+                    }
                 }
             }
         }
diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs
index 98e7067..b3565d4 100644
--- a/src/librustc_mir/util/aggregate.rs
+++ b/src/librustc_mir/util/aggregate.rs
@@ -24,7 +24,7 @@
             if adt_def.is_enum() {
                 set_discriminant = Some(Statement {
                     kind: StatementKind::SetDiscriminant {
-                        place: lhs.clone(),
+                        place: box(lhs.clone()),
                         variant_index,
                     },
                     source_info,
@@ -39,7 +39,7 @@
             let variant_index = VariantIdx::new(0);
             set_discriminant = Some(Statement {
                 kind: StatementKind::SetDiscriminant {
-                    place: lhs.clone(),
+                    place: box(lhs.clone()),
                     variant_index,
                 },
                 source_info,
@@ -70,7 +70,7 @@
         };
         Statement {
             source_info,
-            kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
+            kind: StatementKind::Assign(box(lhs_field, Rvalue::Use(op))),
         }
     }).chain(set_discriminant)
 }
diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs
index b8ef77d..a75c1af 100644
--- a/src/librustc_mir/util/alignment.rs
+++ b/src/librustc_mir/util/alignment.rs
@@ -38,14 +38,15 @@
 where
     L: HasLocalDecls<'tcx>,
 {
-    let mut place_projection = &place.projection;
+    let mut cursor = &*place.projection;
+    while let [proj_base @ .., elem] = cursor {
+        cursor = proj_base;
 
-    while let Some(proj) = place_projection {
-        match proj.elem {
+        match elem {
             // encountered a Deref, which is ABI-aligned
             ProjectionElem::Deref => break,
             ProjectionElem::Field(..) => {
-                let ty = Place::ty_from(&place.base, &proj.base, local_decls, tcx).ty;
+                let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
                 match ty.sty {
                     ty::Adt(def, _) if def.repr.packed() => {
                         return true
@@ -55,7 +56,6 @@
             }
             _ => {}
         }
-        place_projection = &proj.base;
     }
 
     false
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index f3e03e7..52ad97b 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -586,10 +586,7 @@
                 BorrowKind::Mut { allow_two_phase_borrow: false },
                 Place {
                     base: PlaceBase::Local(cur),
-                    projection: Some(Box::new(Projection {
-                        base: None,
-                        elem: ProjectionElem::Deref,
-                    })),
+                    projection: Box::new([ProjectionElem::Deref]),
                 }
              ),
              Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
@@ -981,7 +978,7 @@
     fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
         Statement {
             source_info: self.source_info,
-            kind: StatementKind::Assign(lhs.clone(), box rhs)
+            kind: StatementKind::Assign(box(lhs.clone(), rhs))
         }
     }
 }
diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs
index eb457da..2ea9924 100644
--- a/src/librustc_mir/util/patch.rs
+++ b/src/librustc_mir/util/patch.rs
@@ -120,7 +120,7 @@
     }
 
     pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
-        self.add_statement(loc, StatementKind::Assign(place, box rv));
+        self.add_statement(loc, StatementKind::Assign(box(place, rv)));
     }
 
     pub fn make_nop(&mut self, loc: Location) {
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index ac27019..c35c9e4 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -227,12 +227,12 @@
     pass_name: &str,
     disambiguator: &dyn Display,
     source: MirSource<'tcx>,
-) -> io::Result<fs::File> {
+) -> io::Result<io::BufWriter<fs::File>> {
     let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, source);
     if let Some(parent) = file_path.parent() {
         fs::create_dir_all(parent)?;
     }
-    fs::File::create(&file_path)
+    Ok(io::BufWriter::new(fs::File::create(&file_path)?))
 }
 
 /// Write out a human-readable textual representation for the given MIR.
diff --git a/src/librustc_msan/build.rs b/src/librustc_msan/build.rs
index de1676f..a81786e 100644
--- a/src/librustc_msan/build.rs
+++ b/src/librustc_msan/build.rs
@@ -4,6 +4,7 @@
 use cmake::Config;
 
 fn main() {
+    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
     if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
         return;
     }
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index cf2da4f..a5a8315 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -8,7 +8,7 @@
 
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![feature(bind_by_move_pattern_guards)]
+#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
 
 #![recursion_limit="256"]
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 333509e..11dcf5b 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -31,7 +31,7 @@
 use syntax::attr;
 
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
-use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant};
+use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
 use syntax::ext::expand::AstFragment;
 use syntax::ext::hygiene::ExpnId;
@@ -580,7 +580,7 @@
     }
 
     /// Constructs the reduced graph for one item.
-    fn build_reduced_graph_for_item(&mut self, item: &Item) {
+    fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
         let parent_scope = &self.parent_scope;
         let parent = parent_scope.module;
         let expansion = parent_scope.expansion;
@@ -716,12 +716,10 @@
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
-            ItemKind::Enum(ref enum_definition, _) => {
-                let module_kind = ModuleKind::Def(
-                    DefKind::Enum,
-                    self.r.definitions.local_def_id(item.id),
-                    ident.name,
-                );
+            ItemKind::Enum(_, _) => {
+                let def_id = self.r.definitions.local_def_id(item.id);
+                self.r.variant_vis.insert(def_id, vis);
+                let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name);
                 let module = self.r.new_module(parent,
                                              module_kind,
                                              parent.normal_ancestor_id,
@@ -729,10 +727,6 @@
                                              item.span);
                 self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.parent_scope.module = module;
-
-                for variant in &(*enum_definition).variants {
-                    self.build_reduced_graph_for_variant(variant, vis);
-                }
             }
 
             ItemKind::TraitAlias(..) => {
@@ -817,38 +811,6 @@
         }
     }
 
-    // Constructs the reduced graph for one variant. Variants exist in the
-    // type and value namespaces.
-    fn build_reduced_graph_for_variant(&mut self, variant: &Variant, vis: ty::Visibility) {
-        let parent = self.parent_scope.module;
-        let expn_id = self.parent_scope.expansion;
-        let ident = variant.ident;
-
-        // Define a name in the type namespace.
-        let def_id = self.r.definitions.local_def_id(variant.id);
-        let res = Res::Def(DefKind::Variant, def_id);
-        self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
-
-        // If the variant is marked as non_exhaustive then lower the visibility to within the
-        // crate.
-        let mut ctor_vis = vis;
-        let has_non_exhaustive = attr::contains_name(&variant.attrs, sym::non_exhaustive);
-        if has_non_exhaustive && vis == ty::Visibility::Public {
-            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-        }
-
-        // Define a constructor name in the value namespace.
-        // Braced variants, unlike structs, generate unusable names in
-        // value namespace, they are reserved for possible future use.
-        // It's ok to use the variant's id as a ctor id since an
-        // error will be reported on any use of such resolution anyway.
-        let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id);
-        let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id);
-        let ctor_kind = CtorKind::from_ast(&variant.data);
-        let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
-        self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
-    }
-
     /// Constructs the reduced graph for one foreign item.
     fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
         let (res, ns) = match item.node {
@@ -1188,7 +1150,6 @@
             ItemKind::Mod(..) => self.contains_macro_use(&item.attrs),
             _ => false,
         };
-
         let orig_current_module = self.parent_scope.module;
         let orig_current_legacy_scope = self.parent_scope.legacy;
         self.build_reduced_graph_for_item(item);
@@ -1271,4 +1232,92 @@
         }
         visit::walk_attribute(self, attr);
     }
+
+    fn visit_arm(&mut self, arm: &'b ast::Arm) {
+        if arm.is_placeholder {
+            self.visit_invoc(arm.id);
+        } else {
+            visit::walk_arm(self, arm);
+        }
+    }
+
+    fn visit_field(&mut self, f: &'b ast::Field) {
+        if f.is_placeholder {
+            self.visit_invoc(f.id);
+        } else {
+            visit::walk_field(self, f);
+        }
+    }
+
+    fn visit_field_pattern(&mut self, fp: &'b ast::FieldPat) {
+        if fp.is_placeholder {
+            self.visit_invoc(fp.id);
+        } else {
+            visit::walk_field_pattern(self, fp);
+        }
+    }
+
+    fn visit_generic_param(&mut self, param: &'b ast::GenericParam) {
+        if param.is_placeholder {
+            self.visit_invoc(param.id);
+        } else {
+            visit::walk_generic_param(self, param);
+        }
+    }
+
+    fn visit_param(&mut self, p: &'b ast::Param) {
+        if p.is_placeholder {
+            self.visit_invoc(p.id);
+        } else {
+            visit::walk_param(self, p);
+        }
+    }
+
+    fn visit_struct_field(&mut self, sf: &'b ast::StructField) {
+        if sf.is_placeholder {
+            self.visit_invoc(sf.id);
+        } else {
+            visit::walk_struct_field(self, sf);
+        }
+    }
+
+    // Constructs the reduced graph for one variant. Variants exist in the
+    // type and value namespaces.
+    fn visit_variant(&mut self, variant: &'b ast::Variant) {
+        if variant.is_placeholder {
+            self.visit_invoc(variant.id);
+            return;
+        }
+
+        let parent = self.parent_scope.module;
+        let vis = self.r.variant_vis[&parent.def_id().expect("enum without def-id")];
+        let expn_id = self.parent_scope.expansion;
+        let ident = variant.ident;
+
+        // Define a name in the type namespace.
+        let def_id = self.r.definitions.local_def_id(variant.id);
+        let res = Res::Def(DefKind::Variant, def_id);
+        self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
+
+        // If the variant is marked as non_exhaustive then lower the visibility to within the
+        // crate.
+        let mut ctor_vis = vis;
+        let has_non_exhaustive = attr::contains_name(&variant.attrs, sym::non_exhaustive);
+        if has_non_exhaustive && vis == ty::Visibility::Public {
+            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+        }
+
+        // Define a constructor name in the value namespace.
+        // Braced variants, unlike structs, generate unusable names in
+        // value namespace, they are reserved for possible future use.
+        // It's ok to use the variant's id as a ctor id since an
+        // error will be reported on any use of such resolution anyway.
+        let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id);
+        let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id);
+        let ctor_kind = CtorKind::from_ast(&variant.data);
+        let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
+        self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
+
+        visit::walk_variant(self, variant);
+    }
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 6e131c0..74f68e5 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -40,7 +40,7 @@
 use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
 use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives};
-use syntax::symbol::{Symbol, kw, sym};
+use syntax::symbol::{kw, sym};
 
 use syntax::visit::{self, Visitor};
 use syntax::attr;
@@ -241,7 +241,7 @@
 
     fn names_to_string(segments: &[Segment]) -> String {
         names_to_string(&segments.iter()
-                            .map(|seg| seg.ident)
+                            .map(|seg| seg.ident.name)
                             .collect::<Vec<_>>())
     }
 }
@@ -951,7 +951,11 @@
     struct_constructors: DefIdMap<(Res, ty::Visibility)>,
 
     /// Features enabled for this crate.
-    active_features: FxHashSet<Symbol>,
+    active_features: FxHashSet<Name>,
+
+    /// Stores enum visibilities to properly build a reduced graph
+    /// when visiting the correspondent variants.
+    variant_vis: DefIdMap<ty::Visibility>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1014,8 +1018,8 @@
     fn resolve_str_path(
         &mut self,
         span: Span,
-        crate_root: Option<Symbol>,
-        components: &[Symbol],
+        crate_root: Option<Name>,
+        components: &[Name],
         ns: Namespace,
     ) -> (ast::Path, Res) {
         let root = if crate_root.is_some() {
@@ -1214,6 +1218,7 @@
                 features.declared_lib_features.iter().map(|(feat, ..)| *feat)
                     .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
                     .collect(),
+            variant_vis: Default::default()
         }
     }
 
@@ -2550,7 +2555,7 @@
     fn add_suggestion_for_rename_of_use(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        name: Symbol,
+        name: Name,
         directive: &ImportDirective<'_>,
         binding_span: Span,
     ) {
@@ -2765,22 +2770,22 @@
     }
 }
 
-fn names_to_string(idents: &[Ident]) -> String {
+fn names_to_string(names: &[Name]) -> String {
     let mut result = String::new();
-    for (i, ident) in idents.iter()
-                            .filter(|ident| ident.name != kw::PathRoot)
+    for (i, name) in names.iter()
+                            .filter(|name| **name != kw::PathRoot)
                             .enumerate() {
         if i > 0 {
             result.push_str("::");
         }
-        result.push_str(&ident.as_str());
+        result.push_str(&name.as_str());
     }
     result
 }
 
 fn path_names_to_string(path: &Path) -> String {
     names_to_string(&path.segments.iter()
-                        .map(|seg| seg.ident)
+                        .map(|seg| seg.ident.name)
                         .collect::<Vec<_>>())
 }
 
@@ -2788,15 +2793,14 @@
 fn module_to_string(module: Module<'_>) -> Option<String> {
     let mut names = Vec::new();
 
-    fn collect_mod(names: &mut Vec<Ident>, module: Module<'_>) {
+    fn collect_mod(names: &mut Vec<Name>, module: Module<'_>) {
         if let ModuleKind::Def(.., name) = module.kind {
             if let Some(parent) = module.parent {
-                names.push(Ident::with_dummy_span(name));
+                names.push(name);
                 collect_mod(names, parent);
             }
         } else {
-            // danger, shouldn't be ident?
-            names.push(Ident::from_str("<opaque>"));
+            names.push(Name::intern("<opaque>"));
             collect_mod(names, module.parent.unwrap());
         }
     }
@@ -2805,9 +2809,8 @@
     if names.is_empty() {
         return None;
     }
-    Some(names_to_string(&names.into_iter()
-                        .rev()
-                        .collect::<Vec<_>>()))
+    names.reverse();
+    Some(names_to_string(&names))
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 8743944..3900a3d 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -16,7 +16,7 @@
 use syntax::edition::Edition;
 use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
-use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
+use syntax::ext::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
 use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind};
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
@@ -225,6 +225,27 @@
             self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
         }
 
+        match invoc.fragment_kind {
+            AstFragmentKind::Arms
+                | AstFragmentKind::Fields
+                | AstFragmentKind::FieldPats
+                | AstFragmentKind::GenericParams
+                | AstFragmentKind::Params
+                | AstFragmentKind::StructFields
+                | AstFragmentKind::Variants =>
+            {
+                if let Res::Def(..) = res {
+                    self.session.span_err(
+                        span,
+                        &format!("expected an inert attribute, found {} {}",
+                                 res.article(), res.descr()),
+                    );
+                    return Ok(InvocationRes::Single(self.dummy_ext(kind)));
+                }
+            },
+            _ => {}
+        }
+
         Ok(InvocationRes::Single(ext))
     }
 
@@ -302,7 +323,7 @@
         self.check_stability_and_deprecation(&ext, path);
 
         Ok(if ext.macro_kind() != kind {
-            let expected = if kind == MacroKind::Attr { "attribute" } else  { kind.descr() };
+            let expected = kind.descr_expected();
             let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path);
             self.session.struct_span_err(path.span, &msg)
                         .span_label(path.span, format!("not {} {}", kind.article(), expected))
@@ -753,9 +774,8 @@
                 }
                 Err(..) => {
                     assert!(initial_binding.is_none());
-                    let bang = if kind == MacroKind::Bang { "!" } else { "" };
-                    let msg =
-                        format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
+                    let expected = kind.descr_expected();
+                    let msg = format!("cannot find {} `{}` in this scope", expected, ident);
                     let mut err = self.session.struct_span_err(ident.span, &msg);
                     self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident);
                     err.emit();
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index ca189e7..e77e829 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -71,7 +71,7 @@
 }
 
 /// One import directive.
-#[derive(Debug,Clone)]
+#[derive(Debug, Clone)]
 crate struct ImportDirective<'a> {
     /// The ID of the `extern crate`, `UseTree` etc that imported this `ImportDirective`.
     ///
@@ -447,12 +447,13 @@
     }
 
     // Define the name or return the existing binding if there is a collision.
-    pub fn try_define(&mut self,
-                      module: Module<'a>,
-                      ident: Ident,
-                      ns: Namespace,
-                      binding: &'a NameBinding<'a>)
-                      -> Result<(), &'a NameBinding<'a>> {
+    pub fn try_define(
+        &mut self,
+        module: Module<'a>,
+        ident: Ident,
+        ns: Namespace,
+        binding: &'a NameBinding<'a>,
+    ) -> Result<(), &'a NameBinding<'a>> {
         let res = binding.res();
         self.check_reserved_macro_name(ident, res);
         self.set_binding_parent_module(binding, module);
@@ -480,8 +481,11 @@
                         };
                         if glob_binding.res() != nonglob_binding.res() &&
                            ns == MacroNS && nonglob_binding.expansion != ExpnId::root() {
-                            resolution.binding = Some(this.ambiguity(AmbiguityKind::GlobVsExpanded,
-                                                                    nonglob_binding, glob_binding));
+                            resolution.binding = Some(this.ambiguity(
+                                AmbiguityKind::GlobVsExpanded,
+                                nonglob_binding,
+                                glob_binding,
+                            ));
                         } else {
                             resolution.binding = Some(nonglob_binding);
                         }
@@ -513,9 +517,11 @@
         })
     }
 
-    fn ambiguity(&self, kind: AmbiguityKind,
-                 primary_binding: &'a NameBinding<'a>, secondary_binding: &'a NameBinding<'a>)
-                 -> &'a NameBinding<'a> {
+    fn ambiguity(
+        &self, kind: AmbiguityKind,
+        primary_binding: &'a NameBinding<'a>,
+        secondary_binding: &'a NameBinding<'a>,
+    ) -> &'a NameBinding<'a> {
         self.arenas.alloc_name_binding(NameBinding {
             ambiguity: Some((secondary_binding, kind)),
             ..primary_binding.clone()
@@ -524,8 +530,12 @@
 
     // Use `f` to mutate the resolution of the name in the module.
     // If the resolution becomes a success, define it in the module's glob importers.
-    fn update_resolution<T, F>(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F)
-                               -> T
+    fn update_resolution<T, F>(
+        &mut self, module: Module<'a>,
+        ident: Ident,
+        ns: Namespace,
+        f: F,
+    ) -> T
         where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
     {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
@@ -627,14 +637,18 @@
             self.finalize_resolutions_in(module);
         }
 
-        let mut has_errors = false;
         let mut seen_spans = FxHashSet::default();
         let mut errors = vec![];
         let mut prev_root_id: NodeId = NodeId::from_u32(0);
-        for i in 0 .. self.r.determined_imports.len() {
-            let import = self.r.determined_imports[i];
+        let determined_imports = mem::take(&mut self.r.determined_imports);
+        let indeterminate_imports = mem::take(&mut self.r.indeterminate_imports);
+
+        for (is_indeterminate, import) in determined_imports
+            .into_iter()
+            .map(|i| (false, i))
+            .chain(indeterminate_imports.into_iter().map(|i| (true, i)))
+        {
             if let Some(err) = self.finalize_import(import) {
-                has_errors = true;
 
                 if let SingleImport { source, ref source_bindings, .. } = import.subclass {
                     if source.name == kw::SelfLower {
@@ -666,21 +680,27 @@
                     errors.push((path, err));
                     prev_root_id = import.root_id;
                 }
+            } else if is_indeterminate {
+                // Consider erroneous imports used to avoid duplicate diagnostics.
+                self.r.used_imports.insert((import.id, TypeNS));
+                let path = import_path_to_string(
+                    &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+                    &import.subclass,
+                    import.span,
+                );
+                let err = UnresolvedImportError {
+                    span: import.span,
+                    label: None,
+                    note: Vec::new(),
+                    suggestion: None,
+                };
+                errors.push((path, err));
             }
         }
 
         if !errors.is_empty() {
             self.throw_unresolved_import_error(errors.clone(), None);
         }
-
-        // Report unresolved imports only if no hard error was already reported
-        // to avoid generating multiple errors on the same import.
-        if !has_errors {
-            for import in &self.r.indeterminate_imports {
-                self.throw_unresolved_import_error(errors, Some(MultiSpan::from(import.span)));
-                break;
-            }
-        }
     }
 
     fn throw_unresolved_import_error(
@@ -835,10 +855,20 @@
     ) -> Option<UnresolvedImportError> {
         let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
-        let path_res = self.r.resolve_path(&directive.module_path, None, &directive.parent_scope,
-                                         true, directive.span, directive.crate_lint());
+        let path_res = self.r.resolve_path(
+            &directive.module_path,
+            None,
+            &directive.parent_scope,
+            true,
+            directive.span,
+            directive.crate_lint(),
+        );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
         directive.vis.set(orig_vis);
+        if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
+            // Consider erroneous imports used to avoid duplicate diagnostics.
+            self.r.used_imports.insert((directive.id, TypeNS));
+        }
         let module = match path_res {
             PathResult::Module(module) => {
                 // Consistency checks, analogous to `finalize_macro_resolutions`.
@@ -895,7 +925,6 @@
                             }
                         }
                     };
-
                     return Some(err);
                 }
                 return None;
@@ -1404,15 +1433,17 @@
     let global = !names.is_empty() && names[0].name == kw::PathRoot;
     if let Some(pos) = pos {
         let names = if global { &names[1..pos + 1] } else { &names[..pos + 1] };
-        names_to_string(names)
+        names_to_string(&names.iter().map(|ident| ident.name).collect::<Vec<_>>())
     } else {
         let names = if global { &names[1..] } else { names };
         if names.is_empty() {
             import_directive_subclass_to_string(subclass)
         } else {
-            format!("{}::{}",
-                    names_to_string(names),
-                    import_directive_subclass_to_string(subclass))
+            format!(
+                "{}::{}",
+                names_to_string(&names.iter().map(|ident| ident.name).collect::<Vec<_>>()),
+                import_directive_subclass_to_string(subclass),
+            )
         }
     }
 }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 12c5ce1..55f6b91 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -130,6 +130,10 @@
         self.save_ctxt.span_from_span(span)
     }
 
+    fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
+        self.save_ctxt.lookup_def_id(ref_id)
+    }
+
     pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
         let crate_root = source_file.map(|source_file| {
@@ -223,13 +227,6 @@
         }
     }
 
-    fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
-        match self.save_ctxt.get_path_res(ref_id) {
-            Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => None,
-            def => Some(def.def_id()),
-        }
-    }
-
     fn process_formals(&mut self, formals: &'l [ast::Param], qualname: &str) {
         for arg in formals {
             self.visit_pat(&arg.pat);
@@ -283,36 +280,32 @@
     ) {
         debug!("process_method: {}:{}", id, ident);
 
-        if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident, span) {
-            let sig_str = crate::make_signature(&sig.decl, &generics);
-            if body.is_some() {
-                self.nest_tables(
-                    id,
-                    |v| v.process_formals(&sig.decl.inputs, &method_data.qualname),
-                );
+        let hir_id = self.tcx.hir().node_to_hir_id(id);
+        self.nest_tables(id, |v| {
+            if let Some(mut method_data) = v.save_ctxt.get_method_data(id, ident, span) {
+                v.process_formals(&sig.decl.inputs, &method_data.qualname);
+                v.process_generic_params(&generics, &method_data.qualname, id);
+
+                method_data.value = crate::make_signature(&sig.decl, &generics);
+                method_data.sig = sig::method_signature(id, ident, generics, sig, &v.save_ctxt);
+
+                v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, hir_id), method_data);
             }
 
-            self.process_generic_params(&generics, &method_data.qualname, id);
+            // walk arg and return types
+            for arg in &sig.decl.inputs {
+                v.visit_ty(&arg.ty);
+            }
 
-            method_data.value = sig_str;
-            method_data.sig = sig::method_signature(id, ident, generics, sig, &self.save_ctxt);
-            let hir_id = self.tcx.hir().node_to_hir_id(id);
-            self.dumper.dump_def(&access_from_vis!(self.save_ctxt, vis, hir_id), method_data);
-        }
+            if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output {
+                v.visit_ty(ret_ty);
+            }
 
-        // walk arg and return types
-        for arg in &sig.decl.inputs {
-            self.visit_ty(&arg.ty);
-        }
-
-        if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output {
-            self.visit_ty(ret_ty);
-        }
-
-        // walk the fn body
-        if let Some(body) = body {
-            self.nest_tables(id, |v| v.visit_block(body));
-        }
+            // walk the fn body
+            if let Some(body) = body {
+                v.visit_block(body);
+            }
+        });
     }
 
     fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
@@ -377,26 +370,31 @@
         ty_params: &'l ast::Generics,
         body: &'l ast::Block,
     ) {
-        if let Some(fn_data) = self.save_ctxt.get_item_data(item) {
-            down_cast_data!(fn_data, DefData, item.span);
-            self.nest_tables(
-                item.id,
-                |v| v.process_formals(&decl.inputs, &fn_data.qualname),
-            );
-            self.process_generic_params(ty_params, &fn_data.qualname, item.id);
-            let hir_id = self.tcx.hir().node_to_hir_id(item.id);
-            self.dumper.dump_def(&access_from!(self.save_ctxt, item, hir_id), fn_data);
-        }
+        let hir_id = self.tcx.hir().node_to_hir_id(item.id);
+        self.nest_tables(item.id, |v| {
+            if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
+                down_cast_data!(fn_data, DefData, item.span);
+                v.process_formals(&decl.inputs, &fn_data.qualname);
+                v.process_generic_params(ty_params, &fn_data.qualname, item.id);
 
-        for arg in &decl.inputs {
-            self.visit_ty(&arg.ty);
-        }
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), fn_data);
+            }
 
-        if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
-            self.visit_ty(&ret_ty);
-        }
+            for arg in &decl.inputs {
+                v.visit_ty(&arg.ty)
+            }
 
-        self.nest_tables(item.id, |v| v.visit_block(&body));
+            if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
+                if let ast::TyKind::ImplTrait(..) = ret_ty.node {
+                    // FIXME: Opaque type desugaring prevents us from easily
+                    // processing trait bounds. See `visit_ty` for more details.
+                } else {
+                    v.visit_ty(&ret_ty);
+                }
+            }
+
+            v.visit_block(&body);
+        });
     }
 
     fn process_static_or_const_item(
@@ -1113,11 +1111,7 @@
                 // FIXME: uses of the assoc type should ideally point to this
                 // 'def' and the name here should be a ref to the def in the
                 // trait.
-                for bound in bounds.iter() {
-                    if let ast::GenericBound::Trait(trait_ref, _) = bound {
-                        self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
-                    }
-                }
+                self.process_bounds(&bounds);
             }
             ast::ImplItemKind::Macro(_) => {}
         }
@@ -1364,10 +1358,10 @@
                 self.visit_ty(&ty);
                 self.process_generic_params(ty_params, &qualname, item.id);
             }
-            OpaqueTy(ref _bounds, ref ty_params) => {
+            OpaqueTy(ref bounds, ref ty_params) => {
                 let qualname = format!("::{}",
                     self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id)));
-                // FIXME do something with _bounds
+
                 let value = String::new();
                 if !self.span.filter_generated(item.ident.span) {
                     let span = self.span_from_span(item.ident.span);
@@ -1393,6 +1387,7 @@
                     );
                 }
 
+                self.process_bounds(bounds);
                 self.process_generic_params(ty_params, &qualname, item.id);
             }
             Mac(_) => (),
@@ -1449,6 +1444,18 @@
                 self.visit_ty(element);
                 self.nest_tables(length.id, |v| v.visit_expr(&length.value));
             }
+            ast::TyKind::ImplTrait(id, ref bounds) => {
+                // FIXME: As of writing, the opaque type lowering introduces
+                // another DefPath scope/segment (used to declare the resulting
+                // opaque type item).
+                // However, the synthetic scope does *not* have associated
+                // typeck tables, which means we can't nest it and we fire an
+                // assertion when resolving the qualified type paths in trait
+                // bounds...
+                // This will panic if called on return type `impl Trait`, which
+                // we guard against in `process_fn`.
+                self.nest_tables(id, |v| v.process_bounds(bounds));
+            }
             _ => visit::walk_ty(self, t),
         }
     }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 4bc098d..055ccf6 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -312,7 +312,7 @@
                     let impl_id = self.next_impl_id();
                     let span = self.span_from_span(sub_span);
 
-                    let type_data = self.lookup_ref_id(typ.id);
+                    let type_data = self.lookup_def_id(typ.id);
                     type_data.map(|type_data| {
                         Data::RelationData(Relation {
                             kind: RelationKind::Impl {
@@ -322,7 +322,7 @@
                             from: id_from_def_id(type_data),
                             to: trait_ref
                                 .as_ref()
-                                .and_then(|t| self.lookup_ref_id(t.ref_id))
+                                .and_then(|t| self.lookup_def_id(t.ref_id))
                                 .map(id_from_def_id)
                                 .unwrap_or_else(|| null_id()),
                         },
@@ -495,7 +495,7 @@
     }
 
     pub fn get_trait_ref_data(&self, trait_ref: &ast::TraitRef) -> Option<Ref> {
-        self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| {
+        self.lookup_def_id(trait_ref.ref_id).and_then(|def_id| {
             let span = trait_ref.path.span;
             if generated_code(span) {
                 return None;
@@ -870,7 +870,7 @@
         })
     }
 
-    fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
+    fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
         match self.get_path_res(ref_id) {
             Res::PrimTy(_) | Res::SelfTy(..) | Res::Err => None,
             def => Some(def.def_id()),
diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs
index 53364e7..f7551aa 100644
--- a/src/librustc_target/spec/apple_base.rs
+++ b/src/librustc_target/spec/apple_base.rs
@@ -51,3 +51,19 @@
     let (major, minor) = macos_deployment_target();
     format!("{}-apple-macosx{}.{}.0", arch, major, minor)
 }
+
+pub fn macos_link_env_remove() -> Vec<String> {
+    let mut env_remove = Vec::with_capacity(2);
+    // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
+    // may occur when we're linking a custom build script while targeting iOS for example.
+    if let Some(sdkroot) = env::var("SDKROOT").ok() {
+        if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
+            env_remove.push("SDKROOT".to_string())
+        }
+    }
+    // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
+    // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
+    // although this is apparently ignored when using the linker at "/usr/bin/ld".
+    env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".to_string());
+    env_remove
+}
diff --git a/src/librustc_target/spec/apple_ios_base.rs b/src/librustc_target/spec/apple_ios_base.rs
index 6d3900c..fdbb1bd 100644
--- a/src/librustc_target/spec/apple_ios_base.rs
+++ b/src/librustc_target/spec/apple_ios_base.rs
@@ -38,9 +38,18 @@
     // SDKROOT; for rustc, the user or build system can set it, or we
     // can fall back to checking for xcrun on PATH.)
     if let Some(sdkroot) = env::var("SDKROOT").ok() {
-        let sdkroot_path = Path::new(&sdkroot);
-        if sdkroot_path.is_absolute() && sdkroot_path != Path::new("/") && sdkroot_path.exists() {
-            return Ok(sdkroot);
+        let p = Path::new(&sdkroot);
+        match sdk_name {
+            // Ignore `SDKROOT` if it's clearly set for the wrong platform.
+            "iphoneos" if sdkroot.contains("iPhoneSimulator.platform")
+                       || sdkroot.contains("MacOSX.platform") => (),
+            "iphonesimulator" if sdkroot.contains("iPhoneOS.platform")
+                              || sdkroot.contains("MacOSX.platform") => (),
+            "macosx10.15" if sdkroot.contains("iPhoneOS.platform")
+                          || sdkroot.contains("iPhoneSimulator.platform") => (),
+            // Ignore `SDKROOT` if it's not a valid path.
+            _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => (),
+            _ => return Ok(sdkroot),
         }
     }
     let res = Command::new("xcrun")
@@ -100,6 +109,13 @@
     }.to_string()
 }
 
+fn link_env_remove(arch: Arch) -> Vec<String> {
+    match arch {
+        Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()],
+        X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()],
+    }
+}
+
 pub fn opts(arch: Arch) -> Result<TargetOptions, String> {
     let pre_link_args = build_pre_link_args(arch)?;
     Ok(TargetOptions {
@@ -107,6 +123,7 @@
         dynamic_linking: false,
         executables: true,
         pre_link_args,
+        link_env_remove: link_env_remove(arch),
         has_elf_tls: false,
         eliminate_frame_pointer: false,
         .. super::apple_base::opts()
diff --git a/src/librustc_target/spec/i686_apple_darwin.rs b/src/librustc_target/spec/i686_apple_darwin.rs
index 7d804ea..27d0582 100644
--- a/src/librustc_target/spec/i686_apple_darwin.rs
+++ b/src/librustc_target/spec/i686_apple_darwin.rs
@@ -5,6 +5,7 @@
     base.cpu = "yonah".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
+    base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
     base.stack_probes = true;
     base.eliminate_frame_pointer = false;
 
diff --git a/src/librustc_target/spec/i686_unknown_uefi.rs b/src/librustc_target/spec/i686_unknown_uefi.rs
new file mode 100644
index 0000000..c60f7b4
--- /dev/null
+++ b/src/librustc_target/spec/i686_unknown_uefi.rs
@@ -0,0 +1,98 @@
+// This defines the ia32 target for UEFI systems as described in the UEFI specification. See the
+// uefi-base module for generic UEFI options. On ia32 systems
+// UEFI systems always run in protected-mode, have the interrupt-controller pre-configured and
+// force a single-CPU execution.
+// The cdecl ABI is used. It differs from the stdcall or fastcall ABI.
+// "i686-unknown-windows" is used to get the minimal subset of windows-specific features.
+
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::uefi_base::opts();
+    base.cpu = "pentium4".to_string();
+    base.max_atomic_width = Some(64);
+
+    // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
+    // enable these CPU features explicitly before their first use, otherwise their instructions
+    // will trigger an exception. Rust does not inject any code that enables AVX/MMX/SSE
+    // instruction sets, so this must be done by the firmware. However, existing firmware is known
+    // to leave these uninitialized, thus triggering exceptions if we make use of them. Which is
+    // why we avoid them and instead use soft-floats. This is also what GRUB and friends did so
+    // far.
+    // If you initialize FP units yourself, you can override these flags with custom linker
+    // arguments, thus giving you access to full MMX/SSE acceleration.
+    base.features = "-mmx,-sse,+soft-float".to_string();
+
+    // UEFI mirrors the calling-conventions used on windows. In case of i686 this means small
+    // structs will be returned as int. This shouldn't matter much, since the restrictions placed
+    // by the UEFI specifications forbid any ABI to return structures.
+    base.abi_return_struct_as_int = true;
+
+    // Use -GNU here, because of the reason below:
+    // Backgound and Problem:
+    //   If we use i686-unknown-windows, the LLVM IA32 MSVC generates compiler intrinsic
+    //   _alldiv, _aulldiv, _allrem, _aullrem, _allmul, which will cause undefined symbol.
+    //   A real issue is __aulldiv() is refered by __udivdi3() - udivmod_inner!(), from
+    //   https://github.com/rust-lang-nursery/compiler-builtins.
+    //   As result, rust-lld generates link error finally.
+    // Root-cause:
+    //   In rust\src\llvm-project\llvm\lib\Target\X86\X86ISelLowering.cpp,
+    //   we have below code to use MSVC intrinsics. It assumes MSVC target
+    //   will link MSVC library. But that is NOT true in UEFI environment.
+    //   UEFI does not link any MSVC or GCC standard library.
+    //      if (Subtarget.isTargetKnownWindowsMSVC() ||
+    //          Subtarget.isTargetWindowsItanium()) {
+    //        // Setup Windows compiler runtime calls.
+    //        setLibcallName(RTLIB::SDIV_I64, "_alldiv");
+    //        setLibcallName(RTLIB::UDIV_I64, "_aulldiv");
+    //        setLibcallName(RTLIB::SREM_I64, "_allrem");
+    //        setLibcallName(RTLIB::UREM_I64, "_aullrem");
+    //        setLibcallName(RTLIB::MUL_I64, "_allmul");
+    //        setLibcallCallingConv(RTLIB::SDIV_I64, CallingConv::X86_StdCall);
+    //        setLibcallCallingConv(RTLIB::UDIV_I64, CallingConv::X86_StdCall);
+    //        setLibcallCallingConv(RTLIB::SREM_I64, CallingConv::X86_StdCall);
+    //        setLibcallCallingConv(RTLIB::UREM_I64, CallingConv::X86_StdCall);
+    //        setLibcallCallingConv(RTLIB::MUL_I64, CallingConv::X86_StdCall);
+    //      }
+    //   The compiler intrisics should be implemented by compiler-builtins.
+    //   Unfortunately, compiler-builtins has not provided those intrinsics yet. Such as:
+    //      i386/divdi3.S
+    //      i386/lshrdi3.S
+    //      i386/moddi3.S
+    //      i386/muldi3.S
+    //      i386/udivdi3.S
+    //      i386/umoddi3.S
+    // Possible solution:
+    //   1. Eliminate Intrinsics generation.
+    //      1.1 Choose differnt target to bypass isTargetKnownWindowsMSVC().
+    //      1.2 Remove the "Setup Windows compiler runtime calls" in LLVM
+    //   2. Implement Intrinsics.
+    //   We evaluated all options.
+    //   #2 is hard because we need implement the intrinsics (_aulldiv) generated
+    //   from the other intrinscis (__udivdi3) implementation with the same
+    //   functionality (udivmod_inner). If we let _aulldiv() call udivmod_inner!(),
+    //   then we are in loop. We may have to find another way to implement udivmod_inner!().
+    //   #1.2 may break the existing usage.
+    //   #1.1 seems the simplest solution today.
+    //   The IA32 -gnu calling convention is same as the one defined in UEFI specification.
+    //   It uses cdecl, EAX/ECX/EDX as volatile register, and EAX/EDX as return value.
+    //   We also checked the LLVM X86TargetLowering, the differences between -gnu and -msvc
+    //   is fmodf(f32), longjmp() and TLS. None of them impacts the UEFI code.
+    // As a result, we choose -gnu for i686 version before those intrisics are implemented in
+    // compiler-builtins. After compiler-builtins implements all required intrinsics, we may
+    // remove -gnu and use the default one.
+    Ok(Target {
+        llvm_target: "i686-unknown-windows-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
+        target_os: "uefi".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        arch: "x86".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
+
+        options: base,
+    })
+}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 503d8a0..626fa37 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -493,6 +493,7 @@
     ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
 
     ("x86_64-unknown-uefi", x86_64_unknown_uefi),
+    ("i686-unknown-uefi", i686_unknown_uefi),
 
     ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda),
 
@@ -580,8 +581,10 @@
     /// user-defined libraries.
     pub post_link_args: LinkArgs,
 
-    /// Environment variables to be set before invoking the linker.
+    /// Environment variables to be set for the linker invocation.
     pub link_env: Vec<(String, String)>,
+    /// Environment variables to be removed for the linker invocation.
+    pub link_env_remove: Vec<String>,
 
     /// Extra arguments to pass to the external assembler (when used)
     pub asm_args: Vec<String>,
@@ -843,6 +846,7 @@
             post_link_objects_crt: Vec::new(),
             late_link_args: LinkArgs::new(),
             link_env: Vec::new(),
+            link_env_remove: Vec::new(),
             archive_format: "gnu".to_string(),
             custom_unwind_resume: false,
             allow_asm: true,
@@ -1118,6 +1122,7 @@
         key!(post_link_objects_crt, list);
         key!(post_link_args, link_args);
         key!(link_env, env);
+        key!(link_env_remove, list);
         key!(asm_args, list);
         key!(cpu);
         key!(features);
@@ -1334,6 +1339,7 @@
         target_option_val!(post_link_objects_crt);
         target_option_val!(link_args - post_link_args);
         target_option_val!(env - link_env);
+        target_option_val!(link_env_remove);
         target_option_val!(asm_args);
         target_option_val!(cpu);
         target_option_val!(features);
diff --git a/src/librustc_target/spec/wasm32_wasi.rs b/src/librustc_target/spec/wasm32_wasi.rs
index bb33493..86978c0 100644
--- a/src/librustc_target/spec/wasm32_wasi.rs
+++ b/src/librustc_target/spec/wasm32_wasi.rs
@@ -97,6 +97,10 @@
     options.crt_static_default = true;
     options.crt_static_respected = true;
 
+    // Allow `+crt-static` to create a "cdylib" output which is just a wasm file
+    // without a main function.
+    options.crt_static_allows_dylibs = true;
+
     Ok(Target {
         llvm_target: "wasm32-wasi".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_target/spec/x86_64_apple_darwin.rs b/src/librustc_target/spec/x86_64_apple_darwin.rs
index 1821034..d059e44 100644
--- a/src/librustc_target/spec/x86_64_apple_darwin.rs
+++ b/src/librustc_target/spec/x86_64_apple_darwin.rs
@@ -6,6 +6,7 @@
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
     base.eliminate_frame_pointer = false;
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
+    base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
     base.stack_probes = true;
 
     // Clang automatically chooses a more specific target based on
diff --git a/src/librustc_tsan/build.rs b/src/librustc_tsan/build.rs
index 6df9691..f9333e1 100644
--- a/src/librustc_tsan/build.rs
+++ b/src/librustc_tsan/build.rs
@@ -4,6 +4,7 @@
 use cmake::Config;
 
 fn main() {
+    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
     if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
         return;
     }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 9e52eae..09e6b76 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -23,6 +23,7 @@
 use crate::require_c_abi_if_c_variadic;
 use smallvec::SmallVec;
 use syntax::ast;
+use syntax::errors::pluralise;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::symbol::sym;
@@ -377,7 +378,7 @@
                     quantifier,
                     bound,
                     kind,
-                    if bound != 1 { "s" } else { "" },
+                    pluralise!(bound),
                 ))
             };
 
@@ -1461,7 +1462,7 @@
         span: Span,
         type_str: &str,
         trait_str: &str,
-        name: &str,
+        name: ast::Name,
     ) {
         let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
         if let (Some(_), Ok(snippet)) = (
@@ -1688,7 +1689,7 @@
                         span,
                         &qself_ty.to_string(),
                         "Trait",
-                        &assoc_ident.as_str(),
+                        assoc_ident.name,
                     );
                 }
                 return Err(ErrorReported);
@@ -1761,7 +1762,7 @@
                 span,
                 "Type",
                 &path_str,
-                &item_segment.ident.as_str(),
+                item_segment.ident.name,
             );
             return tcx.types.err;
         };
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 7427ae9..308a3d8 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -2,7 +2,8 @@
 use crate::check::coercion::CoerceMany;
 use rustc::hir::{self, ExprKind};
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc::traits::{ObligationCause, ObligationCauseCode};
+use rustc::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
+use rustc::traits::{ObligationCauseCode};
 use rustc::ty::Ty;
 use syntax_pos::Span;
 
@@ -146,13 +147,15 @@
                     // The reason for the first arm to fail is not that the match arms diverge,
                     // but rather that there's a prior obligation that doesn't hold.
                     0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
-                    _ => (expr.span, ObligationCauseCode::MatchExpressionArm {
-                        arm_span,
-                        source: match_src,
-                        prior_arms: other_arms.clone(),
-                        last_ty: prior_arm_ty.unwrap(),
-                        discrim_hir_id: discrim.hir_id,
-                    }),
+                    _ => (expr.span,
+                          ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                            arm_span,
+                            source: match_src,
+                            prior_arms: other_arms.clone(),
+                            last_ty: prior_arm_ty.unwrap(),
+                            discrim_hir_id: discrim.hir_id,
+                          })
+                         ),
                 };
                 let cause = self.cause(span, code);
                 coercion.coerce(self, &cause, &arm.body, arm_ty);
@@ -345,11 +348,11 @@
         };
 
         // Finally construct the cause:
-        self.cause(error_sp, ObligationCauseCode::IfExpression {
+        self.cause(error_sp, ObligationCauseCode::IfExpression(box IfExpressionCause {
             then: then_sp,
             outer: outer_sp,
             semicolon: remove_semicolon,
-        })
+        }))
     }
 
     fn demand_discriminant_type(
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index e937042..d626bff 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -529,11 +529,11 @@
                 ); // recreated from (*) above
 
                 // Check that E' = S'.
-                let cause = &self.misc(hir_ty.span);
+                let cause = self.misc(hir_ty.span);
                 let InferOk {
                     value: (),
                     obligations,
-                } = self.at(cause, self.param_env)
+                } = self.at(&cause, self.param_env)
                     .eq(*expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
 
@@ -549,7 +549,7 @@
                 );
                 all_obligations.push(
                     Obligation::new(
-                        cause.clone(),
+                        cause,
                         self.param_env,
                         ty::Predicate::TypeOutlives(
                             ty::Binder::dummy(
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 8e187b7..51adf50 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -10,6 +10,7 @@
 use errors::{Applicability, DiagnosticId};
 
 use syntax_pos::Span;
+use syntax::errors::pluralise;
 
 use super::{Inherited, FnCtxt, potentially_plural_count};
 
@@ -308,7 +309,7 @@
 
             let cause = ObligationCause {
                 span: impl_err_span,
-                ..cause.clone()
+                ..cause
             };
 
             let mut diag = struct_span_err!(tcx.sess,
@@ -648,9 +649,9 @@
                      declaration has {} {kind} parameter{}",
                     trait_.ident,
                     impl_count,
-                    if impl_count != 1 { "s" } else { "" },
+                    pluralise!(impl_count),
                     trait_count,
-                    if trait_count != 1 { "s" } else { "" },
+                    pluralise!(trait_count),
                     kind = kind,
                 ),
                 DiagnosticId::Error("E0049".into()),
@@ -665,7 +666,7 @@
                         "expected {} {} parameter{}",
                         trait_count,
                         kind,
-                        if trait_count != 1 { "s" } else { "" },
+                        pluralise!(trait_count),
                     ));
                 }
                 for span in spans {
@@ -680,7 +681,7 @@
                     "found {} {} parameter{}{}",
                     impl_count,
                     kind,
-                    if impl_count != 1 { "s" } else { "" },
+                    pluralise!(impl_count),
                     suffix.unwrap_or_else(|| String::new()),
                 ));
             }
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index da72dfd..56bd903 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -813,18 +813,20 @@
         error: MethodError<'tcx>
     ) {
         let rcvr = &args[0];
-        let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
-            if let Ok(pick) = self.lookup_probe(
-                span,
-                segment.ident,
-                new_rcvr_t,
-                rcvr,
-                probe::ProbeScope::AllTraits,
-            ) {
-                err.span_label(
-                    pick.item.ident.span,
-                    &format!("the method is available for `{}` here", new_rcvr_t),
-                );
+        let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, rcvr_t, lang_item| {
+            if let Some(new_rcvr_t) = self.tcx.mk_lang_item(rcvr_t, lang_item) {
+                if let Ok(pick) = self.lookup_probe(
+                    span,
+                    segment.ident,
+                    new_rcvr_t,
+                    rcvr,
+                    probe::ProbeScope::AllTraits,
+                ) {
+                    err.span_label(
+                        pick.item.ident.span,
+                        &format!("the method is available for `{}` here", new_rcvr_t),
+                    );
+                }
             }
         };
 
@@ -840,17 +842,10 @@
                 // Try alternative arbitrary self types that could fulfill this call.
                 // FIXME: probe for all types that *could* be arbitrary self-types, not
                 // just this whitelist.
-                let box_rcvr_t = self.tcx.mk_box(rcvr_t);
-                try_alt_rcvr(&mut err, box_rcvr_t);
-                let pin_rcvr_t = self.tcx.mk_lang_item(
-                    rcvr_t,
-                    lang_items::PinTypeLangItem,
-                );
-                try_alt_rcvr(&mut err, pin_rcvr_t);
-                let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc);
-                try_alt_rcvr(&mut err, arc_rcvr_t);
-                let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc);
-                try_alt_rcvr(&mut err, rc_rcvr_t);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::OwnedBoxLangItem);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::PinTypeLangItem);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::Arc);
+                try_alt_rcvr(&mut err, rcvr_t, lang_items::Rc);
             }
             err.emit();
         }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 72e6f59..3e45b1e 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -425,6 +425,9 @@
                             "private field"
                         };
                         err.span_label(item_name.span, format!("{}, not a method", field_kind));
+                    } else if lev_candidate.is_none() && static_sources.is_empty() {
+                        err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
+                        self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
                     }
                 } else {
                     err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d8d0162..1197160 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -400,7 +400,7 @@
 
 impl UnsafetyState {
     pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
-        UnsafetyState { def: def, unsafety: unsafety, unsafe_push_count: 0, from_fn: true }
+        UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true }
     }
 
     pub fn recurse(&mut self, blk: &hir::Block) -> UnsafetyState {
@@ -1088,6 +1088,8 @@
 
     let span = body.value.span;
 
+    fn_maybe_err(fcx.tcx, span, fn_sig.abi);
+
     if body.generator_kind.is_some() && can_be_generator.is_some() {
         let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
             kind: TypeVariableOriginKind::TypeInference,
@@ -1439,6 +1441,14 @@
     }
 }
 
+// Forbid defining intrinsics in Rust code,
+// as they must always be defined by the compiler.
+fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
+    if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
+        tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
+    }
+}
+
 pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) {
     debug!(
         "check_item_type(it.hir_id={}, it.name={})",
@@ -1475,9 +1485,17 @@
                 check_on_unimplemented(tcx, trait_def_id, it);
             }
         }
-        hir::ItemKind::Trait(..) => {
+        hir::ItemKind::Trait(_, _, _, _, ref items) => {
             let def_id = tcx.hir().local_def_id(it.hir_id);
             check_on_unimplemented(tcx, def_id, it);
+
+            for item in items.iter() {
+                let item = tcx.hir().trait_item(item.id);
+                if let hir::TraitItemKind::Method(sig, _) = &item.node {
+                    let abi = sig.header.abi;
+                    fn_maybe_err(tcx, item.ident.span, abi);
+                }
+            }
         }
         hir::ItemKind::Struct(..) => {
             check_struct(tcx, it.hir_id, it.span);
@@ -1511,21 +1529,34 @@
             } else {
                 for item in &m.items {
                     let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
-                    if generics.params.len() - generics.own_counts().lifetimes != 0 {
-                        let mut err = struct_span_err!(
+                    let own_counts = generics.own_counts();
+                    if generics.params.len() - own_counts.lifetimes != 0 {
+                        let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
+                            (_, 0) => ("type", "types", Some("u32")),
+                            // We don't specify an example value, because we can't generate
+                            // a valid value for any type.
+                            (0, _) => ("const", "consts", None),
+                            _ => ("type or const", "types or consts", None),
+                        };
+                        struct_span_err!(
                             tcx.sess,
                             item.span,
                             E0044,
-                            "foreign items may not have type parameters"
-                        );
-                        err.span_label(item.span, "can't have type parameters");
-                        // FIXME: once we start storing spans for type arguments, turn this into a
-                        // suggestion.
-                        err.help(
-                            "use specialization instead of type parameters by replacing them \
-                             with concrete types like `u32`",
-                        );
-                        err.emit();
+                            "foreign items may not have {} parameters",
+                            kinds,
+                        ).span_label(
+                            item.span,
+                            &format!("can't have {} parameters", kinds),
+                        ).help(
+                            // FIXME: once we start storing spans for type arguments, turn this
+                            // into a suggestion.
+                            &format!(
+                                "replace the {} parameters with concrete {}{}",
+                                kinds,
+                                kinds_pl,
+                                egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
+                            ),
+                        ).emit();
                     }
 
                     if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 93855a3..18b555d 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -268,7 +268,7 @@
                                 op.node.as_str(), lhs_ty),
                             );
                             let mut suggested_deref = false;
-                            if let Ref(_, mut rty, _) = lhs_ty.sty {
+                            if let Ref(_, rty, _) = lhs_ty.sty {
                                 if {
                                     self.infcx.type_is_copy_modulo_regions(self.param_env,
                                                                            rty,
@@ -279,13 +279,10 @@
                                             .is_ok()
                                 } {
                                     if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
-                                        while let Ref(_, rty_inner, _) = rty.sty {
-                                            rty = rty_inner;
-                                        }
                                         let msg = &format!(
                                             "`{}=` can be used on '{}', you can dereference `{}`",
                                             op.node.as_str(),
-                                            rty,
+                                            rty.peel_refs(),
                                             lstring,
                                         );
                                         err.span_suggestion(
@@ -361,7 +358,7 @@
                             }
 
                             let mut suggested_deref = false;
-                            if let Ref(_, mut rty, _) = lhs_ty.sty {
+                            if let Ref(_, rty, _) = lhs_ty.sty {
                                 if {
                                     self.infcx.type_is_copy_modulo_regions(self.param_env,
                                                                            rty,
@@ -372,17 +369,13 @@
                                             .is_ok()
                                 } {
                                     if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
-                                        while let Ref(_, rty_inner, _) = rty.sty {
-                                            rty = rty_inner;
-                                        }
-                                        let msg = &format!(
-                                                "`{}` can be used on '{}', you can \
-                                                dereference `{2}`: `*{2}`",
-                                                op.node.as_str(),
-                                                rty,
-                                                lstring
-                                        );
-                                        err.help(msg);
+                                        err.help(&format!(
+                                            "`{}` can be used on '{}', you can \
+                                            dereference `{2}`: `*{2}`",
+                                            op.node.as_str(),
+                                            rty.peel_refs(),
+                                            lstring
+                                        ));
                                         suggested_deref = true;
                                     }
                                 }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 312a598..d2e9203 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -519,15 +519,15 @@
     tcx.predicates_of(def_id);
 }
 
-fn convert_enum_variant_types<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn convert_enum_variant_types(
+    tcx: TyCtxt<'_>,
     def_id: DefId,
     variants: &[hir::Variant]
 ) {
     let def = tcx.adt_def(def_id);
     let repr_type = def.repr.discr_type();
     let initial = repr_type.initial_discriminant(tcx);
-    let mut prev_discr = None::<Discr<'tcx>>;
+    let mut prev_discr = None::<Discr<'_>>;
 
     // fill the discriminant values and field types
     for variant in variants {
diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs
index 79a04b9..dd44f86 100644
--- a/src/librustc_typeck/constrained_generic_params.rs
+++ b/src/librustc_typeck/constrained_generic_params.rs
@@ -20,10 +20,10 @@
 }
 
 /// Returns the set of parameters constrained by the impl header.
-pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>,
-                                 impl_trait_ref: Option<ty::TraitRef<'tcx>>)
-                                 -> FxHashSet<Parameter>
-{
+pub fn parameters_for_impl<'tcx>(
+    impl_self_ty: Ty<'tcx>,
+    impl_trait_ref: Option<ty::TraitRef<'tcx>>,
+) -> FxHashSet<Parameter> {
     let vec = match impl_trait_ref {
         Some(tr) => parameters_for(&tr, false),
         None => parameters_for(&impl_self_ty, false),
@@ -36,12 +36,10 @@
 /// uniquely determined by `t` (see RFC 447). If it is true, return the list
 /// of parameters whose values are needed in order to constrain `ty` - these
 /// differ, with the latter being a superset, in the presence of projections.
-pub fn parameters_for<'tcx, T>(t: &T,
-                               include_nonconstraining: bool)
-                               -> Vec<Parameter>
-    where T: TypeFoldable<'tcx>
-{
-
+pub fn parameters_for<'tcx>(
+    t: &impl TypeFoldable<'tcx>,
+    include_nonconstraining: bool,
+) -> Vec<Parameter> {
     let mut collector = ParameterCollector {
         parameters: vec![],
         include_nonconstraining,
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index fcfd9ad..bc0f17c 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -12,7 +12,7 @@
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::def_id::DefId;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc::ty::query::Providers;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -99,6 +99,15 @@
 ) {
     // Every lifetime used in an associated type must be constrained.
     let impl_self_ty = tcx.type_of(impl_def_id);
+    if impl_self_ty.references_error() {
+        // Don't complain about unconstrained type params when self ty isn't known due to errors.
+        // (#36836)
+        tcx.sess.delay_span_bug(
+            tcx.def_span(impl_def_id),
+            "potentially unconstrained type parameters weren't evaluated",
+        );
+        return;
+    }
     let impl_generics = tcx.generics_of(impl_def_id);
     let impl_predicates = tcx.predicates_of(impl_def_id);
     let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index b9b3e62..c3092ce 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -81,10 +81,10 @@
             },
             MetaItemKind::List(ref items) => {
                 let mut sub_cfgs = items.iter().map(Cfg::parse_nested);
-                match &*name.as_str() {
-                    "all" => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)),
-                    "any" => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)),
-                    "not" => if sub_cfgs.len() == 1 {
+                match name {
+                    sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)),
+                    sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)),
+                    sym::not => if sub_cfgs.len() == 1 {
                         Ok(!sub_cfgs.next().unwrap()?)
                     } else {
                         Err(InvalidCfgError {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 38eff43..ae70fdc 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1039,7 +1039,7 @@
     fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
         let empty = cx.tcx.intern_substs(&[]);
-        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
+        let path = external_path(cx, cx.tcx.item_name(did),
             Some(did), false, vec![], empty);
         inline::record_extern_fqn(cx, did, TypeKind::Trait);
         GenericBound::TraitBound(PolyTrait {
@@ -1138,13 +1138,13 @@
 
 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
 // from Fn<(A, B,), C> to Fn(A, B) -> C
-fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option<DefId>, has_self: bool,
+fn external_path(cx: &DocContext<'_>, name: Symbol, trait_did: Option<DefId>, has_self: bool,
                  bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path {
     Path {
         global: false,
         res: Res::Err,
         segments: vec![PathSegment {
-            name: name.to_string(),
+            name: name.as_str().to_string(),
             args: external_generic_args(cx, trait_did, has_self, bindings, substs)
         }],
     }
@@ -1154,7 +1154,7 @@
     fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
         let (trait_ref, ref bounds) = *self;
         inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
-        let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(),
+        let path = external_path(cx, cx.tcx.item_name(trait_ref.def_id),
                                  Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs);
 
         debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
@@ -3089,8 +3089,7 @@
                     AdtKind::Enum => TypeKind::Enum,
                 };
                 inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
-                                         None, false, vec![], substs);
+                let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs);
                 ResolvedPath {
                     path,
                     param_names: None,
@@ -3100,7 +3099,7 @@
             }
             ty::Foreign(did) => {
                 inline::record_extern_fqn(cx, did, TypeKind::Foreign);
-                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
+                let path = external_path(cx, cx.tcx.item_name(did),
                                          None, false, vec![], InternalSubsts::empty());
                 ResolvedPath {
                     path: path,
@@ -3129,7 +3128,7 @@
                 reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b)));
                 for did in dids {
                     let empty = cx.tcx.intern_substs(&[]);
-                    let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
+                    let path = external_path(cx, cx.tcx.item_name(did),
                         Some(did), false, vec![], empty);
                     inline::record_extern_fqn(cx, did, TypeKind::Trait);
                     let bound = GenericBound::TraitBound(PolyTrait {
@@ -3154,7 +3153,7 @@
                     });
                 }
 
-                let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
+                let path = external_path(cx, cx.tcx.item_name(did), Some(did),
                     false, bindings, substs);
                 ResolvedPath {
                     path,
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index d261408..19ea781 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -9,7 +9,7 @@
 use rustc::session::config::{CrateType, parse_crate_types_from_list};
 use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
 use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
-                             get_cmd_lint_options, ExternEntry};
+                             get_cmd_lint_options, host_triple, ExternEntry};
 use rustc::session::search_paths::SearchPath;
 use rustc_driver;
 use rustc_target::spec::TargetTriple;
@@ -54,7 +54,7 @@
     /// Debugging (`-Z`) options to pass to the compiler.
     pub debugging_options: DebuggingOptions,
     /// The target used to compile the crate against.
-    pub target: Option<TargetTriple>,
+    pub target: TargetTriple,
     /// Edition used when reading the crate. Defaults to "2015". Also used by default when
     /// compiling doctests from the crate.
     pub edition: Edition,
@@ -77,6 +77,18 @@
     /// Optional path to persist the doctest executables to, defaults to a
     /// temporary directory if not set.
     pub persist_doctests: Option<PathBuf>,
+    /// Runtool to run doctests with
+    pub runtool: Option<String>,
+    /// Arguments to pass to the runtool
+    pub runtool_args: Vec<String>,
+    /// Whether to allow ignoring doctests on a per-target basis
+    /// For example, using ignore-foo to ignore running the doctest on any target that
+    /// contains "foo" as a substring
+    pub enable_per_target_ignores: bool,
+
+    /// The path to a rustc-like binary to build tests with. If not set, we
+    /// default to loading from $sysroot/bin/rustc.
+    pub test_builder: Option<PathBuf>,
 
     // Options that affect the documentation process
 
@@ -140,6 +152,9 @@
             .field("show_coverage", &self.show_coverage)
             .field("crate_version", &self.crate_version)
             .field("render_options", &self.render_options)
+            .field("runtool", &self.runtool)
+            .field("runtool_args", &self.runtool_args)
+            .field("enable-per-target-ignores", &self.enable_per_target_ignores)
             .finish()
     }
 }
@@ -414,7 +429,9 @@
             }
         }
 
-        let target = matches.opt_str("target").map(|target| {
+        let target = matches.opt_str("target").map_or(
+            TargetTriple::from_triple(host_triple()),
+            |target| {
             if target.ends_with(".json") {
                 TargetTriple::TargetPath(PathBuf::from(target))
             } else {
@@ -463,9 +480,13 @@
         let generate_search_filter = !matches.opt_present("disable-per-crate-search");
         let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from);
         let generate_redirect_pages = matches.opt_present("generate-redirect-pages");
+        let test_builder = matches.opt_str("test-builder").map(PathBuf::from);
         let codegen_options_strs = matches.opt_strs("C");
         let lib_strs = matches.opt_strs("L");
         let extern_strs = matches.opt_strs("extern");
+        let runtool = matches.opt_str("runtool");
+        let runtool_args = matches.opt_strs("runtool-arg");
+        let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
 
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
@@ -496,6 +517,10 @@
             show_coverage,
             crate_version,
             persist_doctests,
+            runtool,
+            runtool_args,
+            enable_per_target_ignores,
+            test_builder,
             render_options: RenderOptions {
                 output,
                 external_html,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 9cfcad4..57b016a 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -13,7 +13,6 @@
 use rustc_driver::abort_on_err;
 use rustc_resolve as resolve;
 use rustc_metadata::cstore::CStore;
-use rustc_target::spec::TargetTriple;
 
 use syntax::source_map;
 use syntax::attr;
@@ -294,7 +293,6 @@
         }
     }).collect();
 
-    let host_triple = TargetTriple::from_triple(config::host_triple());
     let crate_types = if proc_macro_crate {
         vec![config::CrateType::ProcMacro]
     } else {
@@ -313,7 +311,7 @@
         lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)),
         cg: codegen_options,
         externs,
-        target_triple: target.unwrap_or(host_triple),
+        target_triple: target,
         // Ensure that rustdoc works even if rustc is feature-staged
         unstable_features: UnstableFeatures::Allow,
         actually_rustdoc: true,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 74413a7..1a4fa38 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -199,7 +199,7 @@
         let ignore;
         let edition;
         if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
-            let parse_result = LangString::parse(&lang, self.check_error_codes);
+            let parse_result = LangString::parse(&lang, self.check_error_codes, false);
             if !parse_result.rust {
                 return Some(Event::Start(Tag::CodeBlock(lang)));
             }
@@ -272,7 +272,7 @@
             ))
         });
 
-        let tooltip = if ignore {
+        let tooltip = if ignore != Ignore::None {
             Some(("This example is not tested".to_owned(), "ignore"))
         } else if compile_fail {
             Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
@@ -286,7 +286,7 @@
             s.push_str(&highlight::render_with_highlighting(
                 &text,
                 Some(&format!("rust-example-rendered{}",
-                                if ignore { " ignore" }
+                                if ignore != Ignore::None { " ignore" }
                                 else if compile_fail { " compile_fail" }
                                 else if explicit_edition { " edition " }
                                 else { "" })),
@@ -297,7 +297,7 @@
             s.push_str(&highlight::render_with_highlighting(
                 &text,
                 Some(&format!("rust-example-rendered{}",
-                                if ignore { " ignore" }
+                                if ignore != Ignore::None { " ignore" }
                                 else if compile_fail { " compile_fail" }
                                 else if explicit_edition { " edition " }
                                 else { "" })),
@@ -551,7 +551,8 @@
     }
 }
 
-pub fn find_testable_code<T: test::Tester>(doc: &str, tests: &mut T, error_codes: ErrorCodes) {
+pub fn find_testable_code<T: test::Tester>(doc: &str, tests: &mut T, error_codes: ErrorCodes,
+                                           enable_per_target_ignores: bool) {
     let mut parser = Parser::new(doc);
     let mut prev_offset = 0;
     let mut nb_lines = 0;
@@ -564,7 +565,7 @@
                 let block_info = if s.is_empty() {
                     LangString::all_false()
                 } else {
-                    LangString::parse(&*s, error_codes)
+                    LangString::parse(&*s, error_codes, enable_per_target_ignores)
                 };
                 if !block_info.rust {
                     continue;
@@ -607,7 +608,7 @@
     original: String,
     pub should_panic: bool,
     pub no_run: bool,
-    pub ignore: bool,
+    pub ignore: Ignore,
     pub rust: bool,
     pub test_harness: bool,
     pub compile_fail: bool,
@@ -616,13 +617,20 @@
     pub edition: Option<Edition>
 }
 
+#[derive(Eq, PartialEq, Clone, Debug)]
+pub enum Ignore {
+    All,
+    None,
+    Some(Vec<String>),
+}
+
 impl LangString {
     fn all_false() -> LangString {
         LangString {
             original: String::new(),
             should_panic: false,
             no_run: false,
-            ignore: false,
+            ignore: Ignore::None,
             rust: true,  // NB This used to be `notrust = false`
             test_harness: false,
             compile_fail: false,
@@ -632,11 +640,16 @@
         }
     }
 
-    fn parse(string: &str, allow_error_code_check: ErrorCodes) -> LangString {
+    fn parse(
+        string: &str,
+        allow_error_code_check: ErrorCodes,
+        enable_per_target_ignores: bool
+    ) -> LangString {
         let allow_error_code_check = allow_error_code_check.as_bool();
         let mut seen_rust_tags = false;
         let mut seen_other_tags = false;
         let mut data = LangString::all_false();
+        let mut ignores = vec![];
 
         data.original = string.to_owned();
         let tokens = string.split(|c: char|
@@ -651,7 +664,11 @@
                     seen_rust_tags = seen_other_tags == false;
                 }
                 "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; }
-                "ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; }
+                "ignore" => { data.ignore = Ignore::All; seen_rust_tags = !seen_other_tags; }
+                x if x.starts_with("ignore-") => if enable_per_target_ignores {
+                    ignores.push(x.trim_start_matches("ignore-").to_owned());
+                    seen_rust_tags = !seen_other_tags;
+                }
                 "allow_fail" => { data.allow_fail = true; seen_rust_tags = !seen_other_tags; }
                 "rust" => { data.rust = true; seen_rust_tags = true; }
                 "test_harness" => {
@@ -679,6 +696,10 @@
                 _ => { seen_other_tags = true }
             }
         }
+        // ignore-foo overrides ignore
+        if !ignores.is_empty() {
+            data.ignore = Ignore::Some(ignores);
+        }
 
         data.rust &= !seen_other_tags || seen_rust_tags;
 
@@ -919,7 +940,7 @@
                 let lang_string = if syntax.is_empty() {
                     LangString::all_false()
                 } else {
-                    LangString::parse(&*syntax, ErrorCodes::Yes)
+                    LangString::parse(&*syntax, ErrorCodes::Yes, false)
                 };
 
                 if lang_string.rust {
@@ -931,7 +952,10 @@
                             is_fenced = true;
                             previous_offset + fence_idx
                         }
-                        None => offset,
+                        None => {
+                            is_fenced = false;
+                            offset
+                        }
                     };
                 }
             }
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index a95c290..5d6811a 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -1,4 +1,4 @@
-use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
+use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap, Ignore};
 use super::plain_summary_line;
 use std::cell::RefCell;
 use syntax::edition::{Edition, DEFAULT_EDITION};
@@ -26,10 +26,10 @@
 #[test]
 fn test_lang_string_parse() {
     fn t(s: &str,
-        should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
+        should_panic: bool, no_run: bool, ignore: Ignore, rust: bool, test_harness: bool,
         compile_fail: bool, allow_fail: bool, error_codes: Vec<String>,
-         edition: Option<Edition>) {
-        assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString {
+        edition: Option<Edition>) {
+        assert_eq!(LangString::parse(s, ErrorCodes::Yes, true), LangString {
             should_panic,
             no_run,
             ignore,
@@ -42,6 +42,7 @@
             edition,
         })
     }
+    let ignore_foo = Ignore::Some(vec!("foo".to_string()));
 
     fn v() -> Vec<String> {
         Vec::new()
@@ -50,23 +51,24 @@
     // ignore-tidy-linelength
     // marker                | should_panic | no_run | ignore | rust | test_harness
     //                       | compile_fail | allow_fail | error_codes | edition
-    t("",                      false,         false,   false,   true,  false, false, false, v(), None);
-    t("rust",                  false,         false,   false,   true,  false, false, false, v(), None);
-    t("sh",                    false,         false,   false,   false, false, false, false, v(), None);
-    t("ignore",                false,         false,   true,    true,  false, false, false, v(), None);
-    t("should_panic",          true,          false,   false,   true,  false, false, false, v(), None);
-    t("no_run",                false,         true,    false,   true,  false, false, false, v(), None);
-    t("test_harness",          false,         false,   false,   true,  true,  false, false, v(), None);
-    t("compile_fail",          false,         true,    false,   true,  false, true,  false, v(), None);
-    t("allow_fail",            false,         false,   false,   true,  false, false, true,  v(), None);
-    t("{.no_run .example}",    false,         true,    false,   true,  false, false, false, v(), None);
-    t("{.sh .should_panic}",   true,          false,   false,   false, false, false, false, v(), None);
-    t("{.example .rust}",      false,         false,   false,   true,  false, false, false, v(), None);
-    t("{.test_harness .rust}", false,         false,   false,   true,  true,  false, false, v(), None);
-    t("text, no_run",          false,         true,    false,   false, false, false, false, v(), None);
-    t("text,no_run",           false,         true,    false,   false, false, false, false, v(), None);
-    t("edition2015",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2015));
-    t("edition2018",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2018));
+    t("",                      false,         false,   Ignore::None,   true,  false, false, false, v(), None);
+    t("rust",                  false,         false,   Ignore::None,   true,  false, false, false, v(), None);
+    t("sh",                    false,         false,   Ignore::None,   false, false, false, false, v(), None);
+    t("ignore",                false,         false,   Ignore::All,    true,  false, false, false, v(), None);
+    t("ignore-foo",            false,         false,   ignore_foo,     true,  false, false, false, v(), None);
+    t("should_panic",          true,          false,   Ignore::None,   true,  false, false, false, v(), None);
+    t("no_run",                false,         true,    Ignore::None,   true,  false, false, false, v(), None);
+    t("test_harness",          false,         false,   Ignore::None,   true,  true,  false, false, v(), None);
+    t("compile_fail",          false,         true,    Ignore::None,   true,  false, true,  false, v(), None);
+    t("allow_fail",            false,         false,   Ignore::None,   true,  false, false, true,  v(), None);
+    t("{.no_run .example}",    false,         true,    Ignore::None,   true,  false, false, false, v(), None);
+    t("{.sh .should_panic}",   true,          false,   Ignore::None,   false, false, false, false, v(), None);
+    t("{.example .rust}",      false,         false,   Ignore::None,   true,  false, false, false, v(), None);
+    t("{.test_harness .rust}", false,         false,   Ignore::None,   true,  true,  false, false, v(), None);
+    t("text, no_run",          false,         true,    Ignore::None,   false, false, false, false, v(), None);
+    t("text,no_run",           false,         true,    Ignore::None,   false, false, false, false, v(), None);
+    t("edition2015",           false,         false,   Ignore::None,   true,  false, false, false, v(), Some(Edition::Edition2015));
+    t("edition2018",           false,         false,   Ignore::None,   true,  false, false, false, v(), Some(Edition::Edition2018));
 }
 
 #[test]
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 83b0b78..17a940c 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -39,6 +39,14 @@
     };
 }
 
+function getSearchInput() {
+    return document.getElementsByClassName("search-input")[0];
+}
+
+function getSearchElement() {
+    return document.getElementById("search");
+}
+
 (function() {
     "use strict";
 
@@ -71,7 +79,7 @@
                      "derive",
                      "traitalias"];
 
-    var search_input = document.getElementsByClassName("search-input")[0];
+    var search_input = getSearchInput();
 
     // On the search screen, so you remain on the last tab you opened.
     //
@@ -158,7 +166,7 @@
         // If we're in mobile mode, we should add the sidebar in any case.
         hideSidebar();
         var elem;
-        var search = document.getElementById("search");
+        var search = getSearchElement();
         var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
         if (match) {
             from = parseInt(match[1], 10);
@@ -250,7 +258,12 @@
         return String.fromCharCode(c);
     }
 
+    function getHelpElement() {
+        return document.getElementById("help");
+    }
+
     function displayHelp(display, ev, help) {
+        var help = help ? help : getHelpElement();
         if (display === true) {
             if (hasClass(help, "hidden")) {
                 ev.preventDefault();
@@ -264,9 +277,10 @@
         }
     }
 
-    function handleEscape(ev, help) {
+    function handleEscape(ev) {
+        var help = getHelpElement();
+        var search = getSearchElement();
         hideModal();
-        var search = document.getElementById("search");
         if (hasClass(help, "hidden") === false) {
             displayHelp(false, ev, help);
         } else if (hasClass(search, "hidden") === false) {
@@ -284,22 +298,21 @@
             return;
         }
 
-        var help = document.getElementById("help");
         if (document.activeElement.tagName === "INPUT") {
             switch (getVirtualKey(ev)) {
             case "Escape":
-                handleEscape(ev, help);
+                handleEscape(ev);
                 break;
             }
         } else {
             switch (getVirtualKey(ev)) {
             case "Escape":
-                handleEscape(ev, help);
+                handleEscape(ev);
                 break;
 
             case "s":
             case "S":
-                displayHelp(false, ev, help);
+                displayHelp(false, ev);
                 hideModal();
                 ev.preventDefault();
                 focusSearchBar();
@@ -314,7 +327,7 @@
             case "?":
                 if (ev.shiftKey) {
                     hideModal();
-                    displayHelp(true, ev, help);
+                    displayHelp(true, ev);
                 }
                 break;
             }
@@ -1281,9 +1294,7 @@
                 } else if (e.which === 16) { // shift
                     // Does nothing, it's just to avoid losing "focus" on the highlighted element.
                 } else if (e.which === 27) { // escape
-                    removeClass(actives[currentTab][0], "highlighted");
-                    search_input.value = "";
-                    defocusSearchBar();
+                    handleEscape(e);
                 } else if (actives[currentTab].length > 0) {
                     removeClass(actives[currentTab][0], "highlighted");
                 }
@@ -1434,7 +1445,7 @@
                 ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
 
             addClass(main, "hidden");
-            var search = document.getElementById("search");
+            var search = getSearchElement();
             removeClass(search, "hidden");
             search.innerHTML = output;
             var tds = search.getElementsByTagName("td");
@@ -1644,7 +1655,7 @@
                     if (hasClass(main, "content")) {
                         removeClass(main, "hidden");
                     }
-                    var search_c = document.getElementById("search");
+                    var search_c = getSearchElement();
                     if (hasClass(search_c, "content")) {
                         addClass(search_c, "hidden");
                     }
@@ -1691,7 +1702,7 @@
                         if (hasClass(main, "content")) {
                             removeClass(main, "hidden");
                         }
-                        var search_c = document.getElementById("search");
+                        var search_c = getSearchElement();
                         if (hasClass(search_c, "content")) {
                             addClass(search_c, "hidden");
                         }
@@ -2460,7 +2471,7 @@
     var params = getQueryStringParams();
     if (params && params.search) {
         addClass(main, "hidden");
-        var search = document.getElementById("search");
+        var search = getSearchElement();
         removeClass(search, "hidden");
         search.innerHTML = "<h3 style=\"text-align: center;\">Loading search results...</h3>";
     }
@@ -2545,10 +2556,10 @@
 
 // Sets the focus on the search bar at the top of the page
 function focusSearchBar() {
-    document.getElementsByClassName("search-input")[0].focus();
+    getSearchInput().focus();
 }
 
 // Removes the focus from the search bar
 function defocusSearchBar() {
-    document.getElementsByClassName("search-input")[0].blur();
+    getSearchInput().blur();
 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 3019467..0b9e717 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -1,7 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
        html_playground_url = "https://play.rust-lang.org/")]
 
-#![feature(bind_by_move_pattern_guards)]
+#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
 #![feature(rustc_private)]
 #![feature(arbitrary_self_types)]
 #![feature(box_patterns)]
@@ -90,7 +90,7 @@
         32_000_000 // 32MB on other platforms
     };
     rustc_driver::set_sigpipe_handler();
-    env_logger::init();
+    env_logger::init_from_env("RUSTDOC_LOG");
     let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || {
         get_args().map(|args| main_args(&args)).unwrap_or(1)
     }).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE);
@@ -356,6 +356,28 @@
                       "show-coverage",
                       "calculate percentage of public items with documentation")
         }),
+        unstable("enable-per-target-ignores", |o| {
+            o.optflag("",
+                      "enable-per-target-ignores",
+                      "parse ignore-foo for ignoring doctests on a per-target basis")
+        }),
+        unstable("runtool", |o| {
+            o.optopt("",
+                     "runtool",
+                     "",
+                     "The tool to run tests with when building for a different target than host")
+        }),
+        unstable("runtool-arg", |o| {
+            o.optmulti("",
+                       "runtool-arg",
+                       "",
+                       "One (of possibly many) arguments to pass to the runtool")
+        }),
+        unstable("test-builder", |o| {
+            o.optflag("",
+                      "test-builder",
+                      "specified the rustc-like binary to use as the test builder")
+        }),
     ]
 }
 
@@ -451,7 +473,7 @@
     // First, parse the crate and extract all relevant information.
     info!("starting to run rustc");
 
-    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
+    let result = rustc_driver::catch_fatal_errors(move || {
         let crate_name = options.crate_name.clone();
         let crate_version = options.crate_version.clone();
         let (mut krate, renderinfo, renderopts) = core::run_core(options);
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index a30fc05..8431271 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -43,7 +43,7 @@
     edition: Edition
 ) -> i32 {
     let mut output = options.output;
-    output.push(input.file_stem().unwrap());
+    output.push(input.file_name().unwrap());
     output.set_extension("html");
 
     let mut css = String::new();
@@ -143,11 +143,12 @@
     opts.no_crate_inject = true;
     opts.display_warnings = options.display_warnings;
     let mut collector = Collector::new(options.input.display().to_string(), options.clone(),
-                                       true, opts, None, Some(options.input));
+                                       true, opts, None, Some(options.input),
+                                       options.enable_per_target_ignores);
     collector.set_position(DUMMY_SP);
     let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
 
-    find_testable_code(&input_str, &mut collector, codes);
+    find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores);
 
     options.test_args.insert(0, "rustdoctest".to_string());
     testing::test_main(&options.test_args, collector.tests,
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 49a34c7..14f8b16 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -336,7 +336,7 @@
         found_tests: 0,
     };
 
-    find_testable_code(&dox, &mut tests, ErrorCodes::No);
+    find_testable_code(&dox, &mut tests, ErrorCodes::No, false);
 
     if check_missing_code == true && tests.found_tests == 0 {
         let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 000d2843a..482c69c 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_interface::interface;
+use rustc_target::spec::TargetTriple;
 use rustc::hir;
 use rustc::hir::intravisit;
 use rustc::session::{self, config, DiagnosticOutput};
@@ -22,7 +23,7 @@
 
 use crate::clean::Attributes;
 use crate::config::Options;
-use crate::html::markdown::{self, ErrorCodes, LangString};
+use crate::html::markdown::{self, ErrorCodes, LangString, Ignore};
 
 #[derive(Clone, Default)]
 pub struct TestOptions {
@@ -57,6 +58,7 @@
             ..config::basic_debugging_options()
         },
         edition: options.edition,
+        target_triple: options.target.clone(),
         ..config::Options::default()
     };
 
@@ -82,6 +84,7 @@
 
         let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate());
         opts.display_warnings |= options.display_warnings;
+        let enable_per_target_ignores = options.enable_per_target_ignores;
         let mut collector = Collector::new(
             compiler.crate_name()?.peek().to_string(),
             options,
@@ -89,6 +92,7 @@
             opts,
             Some(compiler.source_map().clone()),
             None,
+            enable_per_target_ignores,
         );
 
         let mut global_ctxt = compiler.global_ctxt()?.take();
@@ -181,6 +185,9 @@
     should_panic: bool,
     no_run: bool,
     as_test_harness: bool,
+    runtool: Option<String>,
+    runtool_args: Vec<String>,
+    target: TargetTriple,
     compile_fail: bool,
     mut error_codes: Vec<String>,
     opts: &TestOptions,
@@ -241,7 +248,10 @@
     };
     let output_file = outdir.path().join("rust_out");
 
-    let mut compiler = Command::new(std::env::current_exe().unwrap().with_file_name("rustc"));
+    let rustc_binary = options.test_builder.as_ref().map(|v| &**v).unwrap_or_else(|| {
+        rustc_interface::util::rustc_path().expect("found rustc")
+    });
+    let mut compiler = Command::new(&rustc_binary);
     compiler.arg("--crate-type").arg("bin");
     for cfg in &options.cfgs {
         compiler.arg("--cfg").arg(&cfg);
@@ -270,6 +280,7 @@
     if no_run {
         compiler.arg("--emit=metadata");
     }
+    compiler.arg("--target").arg(target.to_string());
 
     compiler.arg("-");
     compiler.stdin(Stdio::piped());
@@ -315,7 +326,15 @@
     }
 
     // Run the code!
-    let mut cmd = Command::new(output_file);
+    let mut cmd;
+
+    if let Some(tool) = runtool {
+        cmd = Command::new(tool);
+        cmd.arg(output_file);
+        cmd.args(runtool_args);
+    } else {
+        cmd = Command::new(output_file);
+    }
 
     match cmd.output() {
         Err(e) => return Err(TestFailure::ExecutionError(e)),
@@ -407,7 +426,7 @@
                 Ok(Some(item)) => {
                     if !found_main {
                         if let ast::ItemKind::Fn(..) = item.node {
-                            if item.ident.as_str() == "main" {
+                            if item.ident.name == sym::main {
                                 found_main = true;
                             }
                         }
@@ -603,6 +622,7 @@
 
     options: Options,
     use_headers: bool,
+    enable_per_target_ignores: bool,
     cratename: String,
     opts: TestOptions,
     position: Span,
@@ -612,12 +632,14 @@
 
 impl Collector {
     pub fn new(cratename: String, options: Options, use_headers: bool, opts: TestOptions,
-               source_map: Option<Lrc<SourceMap>>, filename: Option<PathBuf>,) -> Collector {
+               source_map: Option<Lrc<SourceMap>>, filename: Option<PathBuf>,
+               enable_per_target_ignores: bool) -> Collector {
         Collector {
             tests: Vec::new(),
             names: Vec::new(),
             options,
             use_headers,
+            enable_per_target_ignores,
             cratename,
             opts,
             position: DUMMY_SP,
@@ -661,12 +683,22 @@
         let opts = self.opts.clone();
         let edition = config.edition.unwrap_or(self.options.edition.clone());
         let options = self.options.clone();
+        let runtool = self.options.runtool.clone();
+        let runtool_args = self.options.runtool_args.clone();
+        let target = self.options.target.clone();
+        let target_str = target.to_string();
 
         debug!("creating test {}: {}", name, test);
         self.tests.push(testing::TestDescAndFn {
             desc: testing::TestDesc {
-                name: testing::DynTestName(name),
-                ignore: config.ignore,
+                name: testing::DynTestName(name.clone()),
+                ignore: match config.ignore {
+                    Ignore::All => true,
+                    Ignore::None => false,
+                    Ignore::Some(ref ignores) => {
+                        ignores.iter().any(|s| target_str.contains(s))
+                    },
+                },
                 // compiler failures are test failures
                 should_panic: testing::ShouldPanic::No,
                 allow_fail: config.allow_fail,
@@ -681,6 +713,9 @@
                     config.should_panic,
                     config.no_run,
                     config.test_harness,
+                    runtool,
+                    runtool_args,
+                    target,
                     config.compile_fail,
                     config.error_codes,
                     &opts,
@@ -827,7 +862,10 @@
         // anything else, this will combine them for us.
         if let Some(doc) = attrs.collapsed_doc_value() {
             self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP));
-            markdown::find_testable_code(&doc, self.collector, self.codes);
+            markdown::find_testable_code(&doc,
+                                         self.collector,
+                                         self.codes,
+                                         self.collector.enable_per_target_ignores);
         }
 
         nested(self);
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index 18a46cf..af1d240 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -25,20 +25,14 @@
 unwind = { path = "../libunwind" }
 hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
 
-[dependencies.backtrace]
-version = "0.3.35"
-default-features = false # don't use coresymbolication on OSX
-features = [
-  "rustc-dep-of-std", # enable build support for integrating into libstd
-  "dbghelp",          # backtrace/symbolize on MSVC
-  "libbacktrace",     # symbolize on most platforms
-  "libunwind",        # backtrace on most platforms
-  "dladdr",           # symbolize on platforms w/o libbacktrace
-]
-optional = true
+[dependencies.backtrace_rs]
+package = "backtrace"
+version = "0.3.37"
+default-features = false # without the libstd `backtrace` feature, stub out everything
+features = [ "rustc-dep-of-std" ] # enable build support for integrating into libstd
 
 [dev-dependencies]
-rand = "0.6.1"
+rand = "0.7"
 
 [target.x86_64-apple-darwin.dependencies]
 rustc_asan = { path = "../librustc_asan" }
@@ -65,6 +59,13 @@
 [features]
 default = ["std_detect_file_io", "std_detect_dlsym_getauxval"]
 
+backtrace = [
+  "backtrace_rs/dbghelp",          # backtrace/symbolize on MSVC
+  "backtrace_rs/libbacktrace",     # symbolize on most platforms
+  "backtrace_rs/libunwind",        # backtrace on most platforms
+  "backtrace_rs/dladdr",           # symbolize on platforms w/o libbacktrace
+]
+
 panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
 compiler-builtins-c = ["alloc/compiler-builtins-c"]
diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
new file mode 100644
index 0000000..61c42a5
--- /dev/null
+++ b/src/libstd/backtrace.rs
@@ -0,0 +1,353 @@
+//! Support for capturing a stack backtrace of an OS thread
+//!
+//! This module contains the support necessary to capture a stack backtrace of a
+//! running OS thread from the OS thread itself. The `Backtrace` type supports
+//! capturing a stack trace via the `Backtrace::capture` and
+//! `Backtrace::force_capture` functions.
+//!
+//! A backtrace is typically quite handy to attach to errors (e.g. types
+//! implementing `std::error::Error`) to get a causal chain of where an error
+//! was generated.
+//!
+//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
+//! > can learn more about its status in the [tracking issue].
+//!
+//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
+//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
+//!
+//! ## Accuracy
+//!
+//! Backtraces are attempted to be as accurate as possible, but no guarantees
+//! are provided about the exact accuracy of a backtrace. Instruction pointers,
+//! symbol names, filenames, line numbers, etc, may all be incorrect when
+//! reported. Accuracy is attempted on a best-effort basis, however, and bugs
+//! are always welcome to indicate areas of improvement!
+//!
+//! For most platforms a backtrace with a filename/line number requires that
+//! programs be compiled with debug information. Without debug information
+//! filenames/line numbers will not be reported.
+//!
+//! ## Platform support
+//!
+//! Not all platforms that libstd compiles for support capturing backtraces.
+//! Some platforms simply do nothing when capturing a backtrace. To check
+//! whether the platform supports capturing backtraces you can consult the
+//! `BacktraceStatus` enum as a result of `Backtrace::status`.
+//!
+//! Like above with accuracy platform support is done on a best effort basis.
+//! Sometimes libraries may not be available at runtime or something may go
+//! wrong which would cause a backtrace to not be captured. Please feel free to
+//! report issues with platforms where a backtrace cannot be captured though!
+//!
+//! ## Environment Variables
+//!
+//! The `Backtrace::capture` function may not actually capture a backtrace by
+//! default. Its behavior is governed by two environment variables:
+//!
+//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture`
+//!   will never capture a backtrace. Any other value this is set to will enable
+//!   `Backtrace::capture`.
+//!
+//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable
+//!   is consulted with the same rules of `RUST_LIB_BACKTRACE`.
+//!
+//! * If neither of the above env vars are set, then `Backtrace::capture` will
+//!   be disabled.
+//!
+//! Capturing a backtrace can be a quite expensive runtime operation, so the
+//! environment variables allow either forcibly disabling this runtime
+//! performance hit or allow selectively enabling it in some programs.
+//!
+//! Note that the `Backtrace::force_capture` function can be used to ignore
+//! these environment variables. Also note that the state of environment
+//! variables is cached once the first backtrace is created, so altering
+//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime may not actually change
+//! how backtraces are captured.
+
+#![unstable(feature = "backtrace", issue = "53487")]
+
+// NB: A note on resolution of a backtrace:
+//
+// Backtraces primarily happen in two steps, one is where we actually capture
+// the stack backtrace, giving us a list of instruction pointers corresponding
+// to stack frames. Next we take these instruction pointers and, one-by-one,
+// turn them into a human readable name (like `main`).
+//
+// The first phase can be somewhat expensive (walking the stack), especially
+// on MSVC where debug information is consulted to return inline frames each as
+// their own frame. The second phase, however, is almost always extremely
+// expensive (on the order of milliseconds sometimes) when it's consulting debug
+// information.
+//
+// We attempt to amortize this cost as much as possible by delaying resolution
+// of an address to a human readable name for as long as possible. When
+// `Backtrace::create` is called to capture a backtrace it doesn't actually
+// perform any symbol resolution, but rather we lazily resolve symbols only just
+// before they're needed for printing. This way we can make capturing a
+// backtrace and throwing it away much cheaper, but actually printing a
+// backtrace is still basically the same cost.
+//
+// This strategy comes at the cost of some synchronization required inside of a
+// `Backtrace`, but that's a relatively small price to pay relative to capturing
+// a backtrace or actually symbolizing it.
+
+use crate::env;
+use crate::fmt;
+use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+use crate::sync::Mutex;
+use crate::sys_common::backtrace::{output_filename, lock};
+use crate::vec::Vec;
+use backtrace_rs as backtrace;
+use backtrace::BytesOrWideString;
+
+/// A captured OS thread stack backtrace.
+///
+/// This type represents a stack backtrace for an OS thread captured at a
+/// previous point in time. In some instances the `Backtrace` type may
+/// internally be empty due to configuration. For more information see
+/// `Backtrace::capture`.
+pub struct Backtrace {
+    inner: Inner,
+}
+
+/// The current status of a backtrace, indicating whether it was captured or
+/// whether it is empty for some other reason.
+#[non_exhaustive]
+#[derive(Debug)]
+pub enum BacktraceStatus {
+    /// Capturing a backtrace is not supported, likely because it's not
+    /// implemented for the current platform.
+    Unsupported,
+    /// Capturing a backtrace has been disabled through either the
+    /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
+    Disabled,
+    /// A backtrace has been captured and the `Backtrace` should print
+    /// reasonable information when rendered.
+    Captured,
+}
+
+enum Inner {
+    Unsupported,
+    Disabled,
+    Captured(Mutex<Capture>),
+}
+
+struct Capture {
+    actual_start: usize,
+    resolved: bool,
+    frames: Vec<BacktraceFrame>,
+}
+
+fn _assert_send_sync() {
+    fn _assert<T: Send + Sync>() {}
+    _assert::<Backtrace>();
+}
+
+struct BacktraceFrame {
+    frame: backtrace::Frame,
+    symbols: Vec<BacktraceSymbol>,
+}
+
+struct BacktraceSymbol {
+    name: Option<Vec<u8>>,
+    filename: Option<BytesOrWide>,
+    lineno: Option<u32>,
+}
+
+enum BytesOrWide {
+    Bytes(Vec<u8>),
+    Wide(Vec<u16>),
+}
+
+impl Backtrace {
+    /// Returns whether backtrace captures are enabled through environment
+    /// variables.
+    fn enabled() -> bool {
+        // Cache the result of reading the environment variables to make
+        // backtrace captures speedy, because otherwise reading environment
+        // variables every time can be somewhat slow.
+        static ENABLED: AtomicUsize = AtomicUsize::new(0);
+        match ENABLED.load(SeqCst) {
+            0 => {}
+            1 => return false,
+            _ => return true,
+        }
+        let enabled = match env::var("RUST_LIB_BACKTRACE") {
+            Ok(s) => s != "0",
+            Err(_) => match env::var("RUST_BACKTRACE") {
+                Ok(s) => s != "0",
+                Err(_) => false,
+            },
+        };
+        ENABLED.store(enabled as usize + 1, SeqCst);
+        return enabled;
+    }
+
+    /// Capture a stack backtrace of the current thread.
+    ///
+    /// This function will capture a stack backtrace of the current OS thread of
+    /// execution, returning a `Backtrace` type which can be later used to print
+    /// the entire stack trace or render it to a string.
+    ///
+    /// This function will be a noop if the `RUST_BACKTRACE` or
+    /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either
+    /// environment variable is set and enabled then this function will actually
+    /// capture a backtrace. Capturing a backtrace can be both memory intensive
+    /// and slow, so these environment variables allow liberally using
+    /// `Backtrace::capture` and only incurring a slowdown when the environment
+    /// variables are set.
+    ///
+    /// To forcibly capture a backtrace regardless of environment variables, use
+    /// the `Backtrace::force_capture` function.
+    #[inline(never)] // want to make sure there's a frame here to remove
+    pub fn capture() -> Backtrace {
+        if !Backtrace::enabled() {
+            return Backtrace { inner: Inner::Disabled };
+        }
+        Backtrace::create(Backtrace::capture as usize)
+    }
+
+    /// Forcibly captures a full backtrace, regardless of environment variable
+    /// configuration.
+    ///
+    /// This function behaves the same as `capture` except that it ignores the
+    /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment
+    /// variables, always capturing a backtrace.
+    ///
+    /// Note that capturing a backtrace can be an expensive operation on some
+    /// platforms, so this should be used with caution in performance-sensitive
+    /// parts of code.
+    #[inline(never)] // want to make sure there's a frame here to remove
+    pub fn force_capture() -> Backtrace {
+        Backtrace::create(Backtrace::force_capture as usize)
+    }
+
+    // Capture a backtrace which start just before the function addressed by
+    // `ip`
+    fn create(ip: usize) -> Backtrace {
+        let _lock = lock();
+        let mut frames = Vec::new();
+        let mut actual_start = None;
+        unsafe {
+            backtrace::trace_unsynchronized(|frame| {
+                frames.push(BacktraceFrame { frame: frame.clone(), symbols: Vec::new() });
+                if frame.symbol_address() as usize == ip && actual_start.is_none() {
+                    actual_start = Some(frames.len());
+                }
+                true
+            });
+        }
+
+        // If no frames came out assume that this is an unsupported platform
+        // since `backtrace` doesn't provide a way of learning this right now,
+        // and this should be a good enough approximation.
+        let inner = if frames.len() == 0 {
+            Inner::Unsupported
+        } else {
+            Inner::Captured(Mutex::new(Capture {
+                actual_start: actual_start.unwrap_or(0),
+                frames,
+                resolved: false,
+            }))
+        };
+
+        Backtrace { inner }
+    }
+
+    /// Returns the status of this backtrace, indicating whether this backtrace
+    /// request was unsupported, disabled, or a stack trace was actually
+    /// captured.
+    pub fn status(&self) -> BacktraceStatus {
+        match self.inner {
+            Inner::Unsupported => BacktraceStatus::Unsupported,
+            Inner::Disabled => BacktraceStatus::Disabled,
+            Inner::Captured(_) => BacktraceStatus::Captured,
+        }
+    }
+}
+
+impl fmt::Display for Backtrace {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(self, fmt)
+    }
+}
+
+impl fmt::Debug for Backtrace {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut capture = match &self.inner {
+            Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
+            Inner::Disabled => return fmt.write_str("disabled backtrace"),
+            Inner::Captured(c) => c.lock().unwrap(),
+        };
+        capture.resolve();
+
+        let full = fmt.alternate();
+        let (frames, style) = if full {
+            (&capture.frames[..], backtrace::PrintFmt::Full)
+        } else {
+            (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
+        };
+
+        // When printing paths we try to strip the cwd if it exists, otherwise
+        // we just print the path as-is. Note that we also only do this for the
+        // short format, because if it's full we presumably want to print
+        // everything.
+        let cwd = crate::env::current_dir();
+        let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
+            output_filename(fmt, path, style, cwd.as_ref().ok())
+        };
+
+        let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
+        f.add_context()?;
+        for frame in frames {
+            let mut f = f.frame();
+            if frame.symbols.is_empty() {
+                f.print_raw(frame.frame.ip(), None, None, None)?;
+            } else {
+                for symbol in frame.symbols.iter() {
+                    f.print_raw(
+                        frame.frame.ip(),
+                        symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
+                        symbol.filename.as_ref().map(|b| match b {
+                            BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
+                            BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
+                        }),
+                        symbol.lineno,
+                    )?;
+                }
+            }
+        }
+        f.finish()?;
+        Ok(())
+    }
+}
+
+impl Capture {
+    fn resolve(&mut self) {
+        // If we're already resolved, nothing to do!
+        if self.resolved {
+            return;
+        }
+        self.resolved = true;
+
+        // Use the global backtrace lock to synchronize this as it's a
+        // requirement of the `backtrace` crate, and then actually resolve
+        // everything.
+        let _lock = lock();
+        for frame in self.frames.iter_mut() {
+            let symbols = &mut frame.symbols;
+            unsafe {
+                backtrace::resolve_frame_unsynchronized(&frame.frame, |symbol| {
+                    symbols.push(BacktraceSymbol {
+                        name: symbol.name().map(|m| m.as_bytes().to_vec()),
+                        filename: symbol.filename_raw().map(|b| match b {
+                            BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
+                            BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
+                        }),
+                        lineno: symbol.lineno(),
+                    });
+                });
+            }
+        }
+    }
+}
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index eca9339..b898936 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -290,7 +290,7 @@
 ///
 /// Note that while concurrent access to environment variables is safe in Rust,
 /// some platforms only expose inherently unsafe non-threadsafe APIs for
-/// inspecting the environment. As a result extra care needs to be taken when
+/// inspecting the environment. As a result, extra care needs to be taken when
 /// auditing calls to unsafe external FFI functions to ensure that any external
 /// environment accesses are properly synchronized with accesses in Rust.
 ///
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 117a430..4a1bb75 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -17,6 +17,7 @@
 
 use crate::alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
 use crate::any::TypeId;
+use crate::backtrace::Backtrace;
 use crate::borrow::Cow;
 use crate::cell;
 use crate::char;
@@ -196,14 +197,28 @@
     #[stable(feature = "error_source", since = "1.30.0")]
     fn source(&self) -> Option<&(dyn Error + 'static)> { None }
 
-    /// Gets the `TypeId` of `self`
+    /// Gets the `TypeId` of `self`.
     #[doc(hidden)]
     #[unstable(feature = "error_type_id",
-               reason = "this is memory unsafe to override in user code",
+               reason = "this is memory-unsafe to override in user code",
                issue = "60784")]
     fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static {
         TypeId::of::<Self>()
     }
+
+    /// Returns a stack backtrace, if available, of where this error ocurred.
+    ///
+    /// This function allows inspecting the location, in code, of where an error
+    /// happened. The returned `Backtrace` contains information about the stack
+    /// trace of the OS thread of execution of where the error originated from.
+    ///
+    /// Note that not all errors contain a `Backtrace`. Also note that a
+    /// `Backtrace` may actually be empty. For more information consult the
+    /// `Backtrace` type itself.
+    #[unstable(feature = "backtrace", issue = "53487")]
+    fn backtrace(&self) -> Option<&Backtrace> {
+        None
+    }
 }
 
 mod private {
@@ -601,19 +616,19 @@
     }
 }
 
-// copied from any.rs
+// Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the boxed type is the same as `T`
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
-        // Get TypeId of the type this function is instantiated with
+        // Get `TypeId` of the type this function is instantiated with.
         let t = TypeId::of::<T>();
 
-        // Get TypeId of the type in the trait object
+        // Get `TypeId` of the type in the trait object.
         let boxed = self.type_id(private::Internal);
 
-        // Compare both TypeIds on equality
+        // Compare both `TypeId`s on equality.
         t == boxed
     }
 
@@ -647,21 +662,21 @@
 }
 
 impl dyn Error + 'static + Send {
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
         <dyn Error + 'static>::is::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
         <dyn Error + 'static>::downcast_ref::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
@@ -670,21 +685,21 @@
 }
 
 impl dyn Error + 'static + Send + Sync {
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
         <dyn Error + 'static>::is::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
         <dyn Error + 'static>::downcast_ref::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Error`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
@@ -695,7 +710,7 @@
 impl dyn Error {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempt to downcast the box to a concrete type.
+    /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
         if self.is::<T>() {
             unsafe {
@@ -863,12 +878,12 @@
 impl dyn Error + Send {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempt to downcast the box to a concrete type.
+    /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>)
                                         -> Result<Box<T>, Box<dyn Error + Send>> {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // reapply the Send marker
+            // Reapply the `Send` marker.
             transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
         })
     }
@@ -877,12 +892,12 @@
 impl dyn Error + Send + Sync {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempt to downcast the box to a concrete type.
+    /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>)
                                         -> Result<Box<T>, Box<Self>> {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // reapply the Send+Sync marker
+            // Reapply the `Send + Sync` marker.
             transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
         })
     }
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 65f4e0c..d7f4cc5 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -615,7 +615,7 @@
 }
 
 // Turns this `CString` into an empty string to prevent
-// memory unsafe code from working by accident. Inline
+// memory-unsafe code from working by accident. Inline
 // to prevent LLVM from optimizing it away in debug builds.
 #[stable(feature = "cstring_drop", since = "1.13.0")]
 impl Drop for CString {
@@ -935,8 +935,10 @@
     /// Wraps a raw C string with a safe C string wrapper.
     ///
     /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
-    /// allows inspection and interoperation of non-owned C strings. This method
-    /// is unsafe for a number of reasons:
+    /// allows inspection and interoperation of non-owned C strings. The total
+    /// size of the raw C string must be smaller than `isize::MAX` **bytes**
+    /// in memory due to calling the `slice::from_raw_parts` function.
+    /// This method is unsafe for a number of reasons:
     ///
     /// * There is no guarantee to the validity of `ptr`.
     /// * The returned lifetime is not guaranteed to be the actual lifetime of
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 5f76875..b5265fe 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1956,7 +1956,8 @@
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to the `opendir` function on Unix
-/// and the `FindFirstFile` function on Windows.
+/// and the `FindFirstFile` function on Windows. Advancing the iterator
+/// currently corresponds to `readdir` on Unix and `FindNextFile` on Windows.
 /// Note that, this [may change in the future][changes].
 ///
 /// [changes]: ../io/index.html#platform-specific-behavior
@@ -2144,7 +2145,7 @@
     use crate::sys_common::io::test::{TempDir, tmpdir};
     use crate::thread;
 
-    use rand::{rngs::StdRng, FromEntropy, RngCore};
+    use rand::{rngs::StdRng, RngCore, SeedableRng};
 
     #[cfg(windows)]
     use crate::os::windows::fs::{symlink_dir, symlink_file};
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index 990c0eb..c798ee0 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -201,9 +201,9 @@
 ///
 /// Each handle returned is a reference to a shared global buffer whose access
 /// is synchronized via a mutex. If you need more explicit control over
-/// locking, see the [`lock() method`][lock].
+/// locking, see the [`Stdin::lock`] method.
 ///
-/// [lock]: struct.Stdin.html#method.lock
+/// [`Stdin::lock`]: struct.Stdin.html#method.lock
 ///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
@@ -425,9 +425,9 @@
 ///
 /// Each handle returned is a reference to a shared global buffer whose access
 /// is synchronized via a mutex. If you need more explicit control over
-/// locking, see the [Stdout::lock] method.
+/// locking, see the [`Stdout::lock`] method.
 ///
-/// [Stdout::lock]: struct.Stdout.html#method.lock
+/// [`Stdout::lock`]: struct.Stdout.html#method.lock
 ///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 71050b0..21aeb9c 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -238,7 +238,7 @@
 #![feature(array_error_internals)]
 #![feature(asm)]
 #![feature(associated_type_bounds)]
-#![feature(bind_by_move_pattern_guards)]
+#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
 #![feature(box_syntax)]
 #![feature(c_variadic)]
 #![feature(cfg_target_has_atomic)]
@@ -452,6 +452,7 @@
 #[macro_use]
 pub mod thread;
 pub mod ascii;
+pub mod backtrace;
 pub mod collections;
 pub mod env;
 pub mod error;
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 952fd9e..28fb402 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -17,8 +17,7 @@
 use crate::raw;
 use crate::sys::stdio::panic_output;
 use crate::sys_common::rwlock::RWLock;
-use crate::sys_common::thread_info;
-use crate::sys_common::util;
+use crate::sys_common::{thread_info, util, backtrace};
 use crate::thread;
 
 #[cfg(not(test))]
@@ -157,20 +156,18 @@
 }
 
 fn default_hook(info: &PanicInfo<'_>) {
-    #[cfg(feature = "backtrace")]
-    use crate::sys_common::backtrace;
-
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
-    #[cfg(feature = "backtrace")]
-    let log_backtrace = {
+    let log_backtrace = if cfg!(feature = "backtrace") {
         let panics = update_panic_count(0);
 
         if panics >= 2 {
-            Some(backtrace::PrintFormat::Full)
+            Some(backtrace_rs::PrintFmt::Full)
         } else {
             backtrace::log_enabled()
         }
+    } else {
+        None
     };
 
     // The current implementation always returns `Some`.
@@ -190,8 +187,7 @@
         let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
                          name, msg, location);
 
-        #[cfg(feature = "backtrace")]
-        {
+        if cfg!(feature = "backtrace") {
             use crate::sync::atomic::{AtomicBool, Ordering};
 
             static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 000f80f..b8d57cf 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -422,7 +422,7 @@
 /// // Execute `ls` in the current directory of the program.
 /// list_dir.status().expect("process failed to execute");
 ///
-/// println!("");
+/// println!();
 ///
 /// // Change `ls` to execute in the root directory.
 /// list_dir.current_dir("/");
@@ -1595,7 +1595,7 @@
 
 /// A trait for implementing arbitrary return types in the `main` function.
 ///
-/// The c-main function only supports to return integers as return type.
+/// The C-main function only supports to return integers as return type.
 /// So, every type implementing the `Termination` trait has to be converted
 /// to an integer.
 ///
diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/fast_thread_local.rs
index 2e02198..8b55939 100644
--- a/src/libstd/sys/vxworks/fast_thread_local.rs
+++ b/src/libstd/sys/vxworks/fast_thread_local.rs
@@ -1,5 +1,3 @@
-// Copyright (c) 2019 Wind River Systems, Inc.
-
 #![cfg(target_thread_local)]
 #![unstable(feature = "thread_local_internals", issue = "0")]
 
diff --git a/src/libstd/sys/vxworks/process/mod.rs b/src/libstd/sys/vxworks/process/mod.rs
index 4dc7060..1fc88fb 100644
--- a/src/libstd/sys/vxworks/process/mod.rs
+++ b/src/libstd/sys/vxworks/process/mod.rs
@@ -1,5 +1,6 @@
 pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
 pub use self::process_inner::Process;
+pub use crate::ffi::OsString as EnvKey;
 
 mod process_common;
 #[path = "process_vxworks.rs"]
diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs
index 5091402..13648ab 100644
--- a/src/libstd/sys/vxworks/process/process_common.rs
+++ b/src/libstd/sys/vxworks/process/process_common.rs
@@ -12,8 +12,6 @@
 
 use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
 
-pub use crate::ffi::OsString as EnvKey;
-
 ////////////////////////////////////////////////////////////////////////////////
 // Command
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs
index b07966f..8780df1 100644
--- a/src/libstd/sys/vxworks/process/process_vxworks.rs
+++ b/src/libstd/sys/vxworks/process/process_vxworks.rs
@@ -5,6 +5,7 @@
 use crate::sys::cvt;
 use crate::sys::process::rtp;
 use crate::sys::process::process_common::*;
+use crate::sys_common::thread;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
@@ -57,8 +58,7 @@
                 self.get_argv().as_ptr() as *const _, // argv
                 *sys::os::environ() as *const *const c_char,
                 100 as c_int,                         // initial priority
-                0x16000,                                    // initial stack size. 0 defaults
-                                                      // to 0x4000 in 32 bit and 0x8000 in 64 bit
+                thread::min_stack(),                  // initial stack size.
                 0,                                    // options
                 0                                     // task options
             );
diff --git a/src/libstd/sys/vxworks/rand.rs b/src/libstd/sys/vxworks/rand.rs
index 1ec0cbe..c22880d 100644
--- a/src/libstd/sys/vxworks/rand.rs
+++ b/src/libstd/sys/vxworks/rand.rs
@@ -14,17 +14,24 @@
 mod imp {
     use libc;
     use crate::io;
-
-    extern "C" {
-        fn randBytes (randBuf: *mut libc::c_uchar,
-                      numOfBytes: libc::c_int) -> libc::c_int;
-    }
+    use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
 
     pub fn fill_bytes(v: &mut [u8]) {
+        static RNG_INIT: AtomicBool = AtomicBool::new(false);
+        while !RNG_INIT.load(Relaxed) {
+            let ret = unsafe { libc::randSecure() };
+            if ret < 0 {
+                panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
+            } else if ret > 0 {
+                RNG_INIT.store(true, Relaxed);
+                break;
+            }
+            unsafe { libc::usleep(10) };
+        }
         let ret = unsafe {
-            randBytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
+            libc::randABytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
         };
-        if ret == -1 {
+        if ret < 0 {
             panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
         }
     }
diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs
index ef896f6..e4396b0 100644
--- a/src/libstd/sys/vxworks/thread.rs
+++ b/src/libstd/sys/vxworks/thread.rs
@@ -8,7 +8,7 @@
 
 use crate::sys_common::thread::*;
 
-pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K
 
 pub struct Thread {
     id: libc::pthread_t,
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index bf37ff7..01711d4 100644
--- a/src/libstd/sys_common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
@@ -2,25 +2,38 @@
 /// supported platforms.
 
 use crate::env;
+use crate::fmt;
 use crate::io;
+use crate::borrow::Cow;
 use crate::io::prelude::*;
-use crate::mem;
-use crate::path::{self, Path};
-use crate::ptr;
-use crate::sync::atomic::{self, Ordering};
+use crate::path::{self, Path, PathBuf};
 use crate::sys::mutex::Mutex;
 
-use backtrace::{BytesOrWideString, Frame, Symbol};
-
-pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::<usize>();
+use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt};
 
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
 
-/// Prints the current backtrace.
-pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
+pub fn lock() -> impl Drop {
+    struct Guard;
     static LOCK: Mutex = Mutex::new();
 
+    impl Drop for Guard {
+        fn drop(&mut self) {
+            unsafe {
+                LOCK.unlock();
+            }
+        }
+    }
+
+    unsafe {
+        LOCK.lock();
+        return Guard;
+    }
+}
+
+/// Prints the current backtrace.
+pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
     // There are issues currently linking libbacktrace into tests, and in
     // general during libstd's own unit tests we're not testing this path. In
     // test mode immediately return here to optimize away any references to the
@@ -32,33 +45,69 @@
     // Use a lock to prevent mixed output in multithreading context.
     // Some platforms also requires it, like `SymFromAddr` on Windows.
     unsafe {
-        LOCK.lock();
-        let res = _print(w, format);
-        LOCK.unlock();
-        res
+        let _lock = lock();
+        _print(w, format)
     }
 }
 
-fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
-    writeln!(w, "stack backtrace:")?;
-
-    let mut printer = Printer::new(format, w);
-    unsafe {
-        backtrace::trace_unsynchronized(|frame| {
-            let mut hit = false;
-            backtrace::resolve_frame_unsynchronized(frame, |symbol| {
-                hit = true;
-                printer.output(frame, Some(symbol));
-            });
-            if !hit {
-                printer.output(frame, None);
-            }
-            !printer.done
-        });
+unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
+    struct DisplayBacktrace {
+        format: PrintFmt,
     }
-    if printer.skipped {
+    impl fmt::Display for DisplayBacktrace {
+        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+            unsafe {
+                _print_fmt(fmt, self.format)
+            }
+        }
+    }
+    write!(w, "{}", DisplayBacktrace { format })
+}
+
+unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
+    let cwd = env::current_dir().ok();
+    let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
+        output_filename(fmt, bows, print_fmt, cwd.as_ref())
+    };
+    let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
+    bt_fmt.add_context()?;
+    let mut idx = 0;
+    let mut res = Ok(());
+    backtrace_rs::trace_unsynchronized(|frame| {
+        if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
+            return false;
+        }
+
+        let mut hit = false;
+        let mut stop = false;
+        backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
+            hit = true;
+            if print_fmt == PrintFmt::Short {
+                if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
+                    if sym.contains("__rust_begin_short_backtrace") {
+                        stop = true;
+                        return;
+                    }
+                }
+            }
+
+            res = bt_fmt.frame().symbol(frame, symbol);
+        });
+        if stop {
+            return false;
+        }
+        if !hit {
+            res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+        }
+
+        idx += 1;
+        res.is_ok()
+    });
+    res?;
+    bt_fmt.finish()?;
+    if print_fmt == PrintFmt::Short {
         writeln!(
-            w,
+            fmt,
             "note: Some details are omitted, \
              run with `RUST_BACKTRACE=full` for a verbose backtrace."
         )?;
@@ -77,33 +126,32 @@
     f()
 }
 
-/// Controls how the backtrace should be formatted.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum PrintFormat {
-    /// Show only relevant data from the backtrace.
-    Short = 2,
-    /// Show all the frames with absolute path for files.
-    Full = 3,
-}
-
 // For now logging is turned off by default, and this function checks to see
 // whether the magical environment variable is present to see if it's turned on.
-pub fn log_enabled() -> Option<PrintFormat> {
+pub fn log_enabled() -> Option<PrintFmt> {
+    use crate::sync::atomic::{self, Ordering};
+
+    // Setting environment variables for Fuchsia components isn't a standard
+    // or easily supported workflow. For now, always display backtraces.
+    if cfg!(target_os = "fuchsia") {
+        return Some(PrintFmt::Full);
+    }
+
     static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
     match ENABLED.load(Ordering::SeqCst) {
         0 => {}
         1 => return None,
-        2 => return Some(PrintFormat::Short),
-        _ => return Some(PrintFormat::Full),
+        2 => return Some(PrintFmt::Short),
+        _ => return Some(PrintFmt::Full),
     }
 
     let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
         if &x == "0" {
             None
         } else if &x == "full" {
-            Some(PrintFormat::Full)
+            Some(PrintFmt::Full)
         } else {
-            Some(PrintFormat::Short)
+            Some(PrintFmt::Short)
         }
     });
     ENABLED.store(
@@ -116,130 +164,43 @@
     val
 }
 
-struct Printer<'a, 'b> {
-    format: PrintFormat,
-    done: bool,
-    skipped: bool,
-    idx: usize,
-    out: &'a mut (dyn Write + 'b),
-}
-
-impl<'a, 'b> Printer<'a, 'b> {
-    fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> {
-        Printer { format, done: false, skipped: false, idx: 0, out }
-    }
-
-    /// Prints the symbol of the backtrace frame.
-    ///
-    /// These output functions should now be used everywhere to ensure consistency.
-    /// You may want to also use `output_fileline`.
-    fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) {
-        if self.idx > MAX_NB_FRAMES {
-            self.done = true;
-            self.skipped = true;
-            return;
+/// Prints the filename of the backtrace frame.
+///
+/// See also `output`.
+pub fn output_filename(
+    fmt: &mut fmt::Formatter<'_>,
+    bows: BytesOrWideString<'_>,
+    print_fmt: PrintFmt,
+    cwd: Option<&PathBuf>,
+) -> fmt::Result {
+    let file: Cow<'_, Path> = match bows {
+        #[cfg(unix)]
+        BytesOrWideString::Bytes(bytes) => {
+            use crate::os::unix::prelude::*;
+            Path::new(crate::ffi::OsStr::from_bytes(bytes)).into()
         }
-        if self._output(frame, symbol).is_err() {
-            self.done = true;
+        #[cfg(not(unix))]
+        BytesOrWideString::Bytes(bytes) => {
+            Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
         }
-        self.idx += 1;
-    }
-
-    fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> {
-        if self.format == PrintFormat::Short {
-            if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) {
-                if sym.contains("__rust_begin_short_backtrace") {
-                    self.skipped = true;
-                    self.done = true;
-                    return Ok(());
-                }
-            }
-
-            // Remove the `17: 0x0 - <unknown>` line.
-            if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() {
-                self.skipped = true;
-                return Ok(());
-            }
-        }
-
-        match self.format {
-            PrintFormat::Full => {
-                write!(self.out, "  {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)?
-            }
-            PrintFormat::Short => write!(self.out, "  {:2}: ", self.idx)?,
-        }
-
-        match symbol.and_then(|s| s.name()) {
-            Some(symbol) => {
-                match self.format {
-                    PrintFormat::Full => write!(self.out, "{}", symbol)?,
-                    // Strip the trailing hash if short mode.
-                    PrintFormat::Short => write!(self.out, "{:#}", symbol)?,
-                }
-            }
-            None => self.out.write_all(b"<unknown>")?,
-        }
-        self.out.write_all(b"\n")?;
-        if let Some(sym) = symbol {
-            self.output_fileline(sym)?;
-        }
-        Ok(())
-    }
-
-    /// Prints the filename and line number of the backtrace frame.
-    ///
-    /// See also `output`.
-    fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> {
         #[cfg(windows)]
-        let path_buf;
-        let file = match symbol.filename_raw() {
-            #[cfg(unix)]
-            Some(BytesOrWideString::Bytes(bytes)) => {
-                use crate::os::unix::prelude::*;
-                Path::new(crate::ffi::OsStr::from_bytes(bytes))
-            }
-            #[cfg(not(unix))]
-            Some(BytesOrWideString::Bytes(bytes)) => {
-                Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
-            }
-            #[cfg(windows)]
-            Some(BytesOrWideString::Wide(wide)) => {
-                use crate::os::windows::prelude::*;
-                path_buf = crate::ffi::OsString::from_wide(wide);
-                Path::new(&path_buf)
-            }
-            #[cfg(not(windows))]
-            Some(BytesOrWideString::Wide(_wide)) => {
-                Path::new("<unknown>")
-            }
-            None => return Ok(()),
-        };
-        let line = match symbol.lineno() {
-            Some(line) => line,
-            None => return Ok(()),
-        };
-        // prior line: "  ##: {:2$} - func"
-        self.out.write_all(b"")?;
-        match self.format {
-            PrintFormat::Full => write!(self.out, "           {:1$}", "", HEX_WIDTH)?,
-            PrintFormat::Short => write!(self.out, "           ")?,
+        BytesOrWideString::Wide(wide) => {
+            use crate::os::windows::prelude::*;
+            Cow::Owned(crate::ffi::OsString::from_wide(wide).into())
         }
-
-        let mut already_printed = false;
-        if self.format == PrintFormat::Short && file.is_absolute() {
-            if let Ok(cwd) = env::current_dir() {
-                if let Ok(stripped) = file.strip_prefix(&cwd) {
-                    if let Some(s) = stripped.to_str() {
-                        write!(self.out, "  at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
-                        already_printed = true;
-                    }
+        #[cfg(not(windows))]
+        BytesOrWideString::Wide(_wide) => {
+            Path::new("<unknown>").into()
+        }
+    };
+    if print_fmt == PrintFmt::Short && file.is_absolute() {
+        if let Some(cwd) = cwd {
+            if let Ok(stripped) = file.strip_prefix(&cwd) {
+                if let Some(s) = stripped.to_str() {
+                    return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
                 }
             }
         }
-        if !already_printed {
-            write!(self.out, "  at {}:{}", file.display(), line)?;
-        }
-
-        self.out.write_all(b"\n")
     }
+    fmt::Display::fmt(&file.display(), fmt)
 }
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index 9190a3b..cba3eca 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -41,7 +41,6 @@
 
 pub mod alloc;
 pub mod at_exit_imp;
-#[cfg(feature = "backtrace")]
 pub mod backtrace;
 pub mod condvar;
 pub mod io;
diff --git a/src/libstd/tests/env.rs b/src/libstd/tests/env.rs
index 06fb553..f8014cb 100644
--- a/src/libstd/tests/env.rs
+++ b/src/libstd/tests/env.rs
@@ -5,7 +5,7 @@
 use rand::distributions::Alphanumeric;
 
 fn make_rand_name() -> OsString {
-    let mut rng = thread_rng();
+    let rng = thread_rng();
     let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10)
                                  .collect::<String>());
     let n = OsString::from(n);
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index d59085c..3bf2b8b 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -59,6 +59,30 @@
 ///    println!("{}", now.elapsed().as_secs());
 /// }
 /// ```
+///
+/// # Underlying System calls
+/// Currently, the following system calls are being used to get the current time using `now()`:
+///
+/// |  Platform |               System call                                            |
+/// |:---------:|:--------------------------------------------------------------------:|
+/// | Cloud ABI | [clock_time_get (Monotonic Clock)]                                   |
+/// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
+/// | UNIX      | [clock_time_get (Monotonic Clock)]                                   |
+/// | Darwin    | [mach_absolute_time]                                                 |
+/// | VXWorks   | [clock_gettime (Monotonic Clock)]                                    |
+/// | WASI      | [__wasi_clock_time_get (Monotonic Clock)]                            |
+/// | Windows   | [QueryPerformanceCounter]                                            |
+///
+/// [QueryPerformanceCounter]: https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter
+/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time
+/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
+/// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#clock_time_get
+/// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime
+/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
+/// [clock_time_get (Monotonic Clock)]: https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt
+///
+/// **Disclaimer:** These system calls might change over time.
+///
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct Instant(time::Instant);
@@ -114,6 +138,28 @@
 ///    }
 /// }
 /// ```
+///
+/// # Underlying System calls
+/// Currently, the following system calls are being used to get the current time using `now()`:
+///
+/// |  Platform |               System call                                            |
+/// |:---------:|:--------------------------------------------------------------------:|
+/// | Cloud ABI | [clock_time_get (Realtime Clock)]                                    |
+/// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
+/// | UNIX      | [clock_gettime (Realtime Clock)]                                     |
+/// | DARWIN    | [gettimeofday]                                                       |
+/// | VXWorks   | [clock_gettime (Realtime Clock)]                                     |
+/// | WASI      | [__wasi_clock_time_get (Realtime Clock)]                             |
+/// | Windows   | [GetSystemTimeAsFileTime]                                            |
+///
+/// [clock_time_get (Realtime Clock)]: https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt
+/// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html
+/// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime
+/// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#clock_time_get
+/// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime
+///
+/// **Disclaimer:** These system calls might change over time.
+///
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct SystemTime(time::SystemTime);
@@ -216,7 +262,7 @@
     }
 
     /// Returns the amount of time elapsed from another instant to this one,
-    /// or None if that instant is earlier than this one.
+    /// or None if that instant is later than this one.
     ///
     /// # Examples
     ///
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index bfb2db9..bcbc0a1 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -352,7 +352,7 @@
     pub ident: Ident,
     pub attrs: ThinVec<Attribute>,
     pub bounds: GenericBounds,
-
+    pub is_placeholder: bool,
     pub kind: GenericParamKind,
 }
 
@@ -613,6 +613,7 @@
     pub attrs: ThinVec<Attribute>,
     pub id: NodeId,
     pub span: Span,
+    pub is_placeholder: bool,
 }
 
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
@@ -935,6 +936,7 @@
     pub body: P<Expr>,
     pub span: Span,
     pub id: NodeId,
+    pub is_placeholder: bool,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -945,6 +947,7 @@
     pub is_shorthand: bool,
     pub attrs: ThinVec<Attribute>,
     pub id: NodeId,
+    pub is_placeholder: bool,
 }
 
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
@@ -1798,6 +1801,7 @@
     pub pat: P<Pat>,
     pub id: NodeId,
     pub span: Span,
+    pub is_placeholder: bool,
 }
 
 /// Alternative representation for `Arg`s describing `self` parameter of methods.
@@ -1859,6 +1863,7 @@
             span,
             ty,
             id: DUMMY_NODE_ID,
+            is_placeholder: false
         };
         match eself.node {
             SelfKind::Explicit(ty, mutbl) => param(mutbl, ty),
@@ -2054,6 +2059,8 @@
     pub disr_expr: Option<AnonConst>,
     /// Span
     pub span: Span,
+    /// Is a macro placeholder
+    pub is_placeholder: bool,
 }
 
 /// Part of `use` item to the right of its prefix.
@@ -2216,6 +2223,7 @@
     pub id: NodeId,
     pub ty: P<Ty>,
     pub attrs: Vec<Attribute>,
+    pub is_placeholder: bool,
 }
 
 /// Fields and constructor ids of enum variants and structs.
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index c4569b3..384c055 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -35,6 +35,13 @@
     ForeignItem(P<ast::ForeignItem>),
     Stmt(P<ast::Stmt>),
     Expr(P<ast::Expr>),
+    Arm(ast::Arm),
+    Field(ast::Field),
+    FieldPat(ast::FieldPat),
+    GenericParam(ast::GenericParam),
+    Param(ast::Param),
+    StructField(ast::StructField),
+    Variant(ast::Variant),
 }
 
 impl HasAttrs for Annotatable {
@@ -46,6 +53,13 @@
             Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs,
             Annotatable::Stmt(ref stmt) => stmt.attrs(),
             Annotatable::Expr(ref expr) => &expr.attrs,
+            Annotatable::Arm(ref arm) => &arm.attrs,
+            Annotatable::Field(ref field) => &field.attrs,
+            Annotatable::FieldPat(ref fp) => &fp.attrs,
+            Annotatable::GenericParam(ref gp) => &gp.attrs,
+            Annotatable::Param(ref p) => &p.attrs,
+            Annotatable::StructField(ref sf) => &sf.attrs,
+            Annotatable::Variant(ref v) => &v.attrs(),
         }
     }
 
@@ -57,6 +71,13 @@
             Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f),
             Annotatable::Stmt(stmt) => stmt.visit_attrs(f),
             Annotatable::Expr(expr) => expr.visit_attrs(f),
+            Annotatable::Arm(arm) => arm.visit_attrs(f),
+            Annotatable::Field(field) => field.visit_attrs(f),
+            Annotatable::FieldPat(fp) => fp.visit_attrs(f),
+            Annotatable::GenericParam(gp) => gp.visit_attrs(f),
+            Annotatable::Param(p) => p.visit_attrs(f),
+            Annotatable::StructField(sf) => sf.visit_attrs(f),
+            Annotatable::Variant(v) => v.visit_attrs(f),
         }
     }
 }
@@ -70,6 +91,13 @@
             Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
             Annotatable::Stmt(ref stmt) => stmt.span,
             Annotatable::Expr(ref expr) => expr.span,
+            Annotatable::Arm(ref arm) => arm.span,
+            Annotatable::Field(ref field) => field.span,
+            Annotatable::FieldPat(ref fp) => fp.pat.span,
+            Annotatable::GenericParam(ref gp) => gp.ident.span,
+            Annotatable::Param(ref p) => p.span,
+            Annotatable::StructField(ref sf) => sf.span,
+            Annotatable::Variant(ref v) => v.span,
         }
     }
 
@@ -81,6 +109,13 @@
             Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item),
             Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt),
             Annotatable::Expr(expr) => visitor.visit_expr(expr),
+            Annotatable::Arm(arm) => visitor.visit_arm(arm),
+            Annotatable::Field(field) => visitor.visit_field(field),
+            Annotatable::FieldPat(fp) => visitor.visit_field_pattern(fp),
+            Annotatable::GenericParam(gp) => visitor.visit_generic_param(gp),
+            Annotatable::Param(p) => visitor.visit_param(p),
+            Annotatable::StructField(sf) =>visitor.visit_struct_field(sf),
+            Annotatable::Variant(v) => visitor.visit_variant(v),
         }
     }
 
@@ -136,6 +171,55 @@
         }
     }
 
+    pub fn expect_arm(self) -> ast::Arm {
+        match self {
+            Annotatable::Arm(arm) => arm,
+            _ => panic!("expected match arm")
+        }
+    }
+
+    pub fn expect_field(self) -> ast::Field {
+        match self {
+            Annotatable::Field(field) => field,
+            _ => panic!("expected field")
+        }
+    }
+
+    pub fn expect_field_pattern(self) -> ast::FieldPat {
+        match self {
+            Annotatable::FieldPat(fp) => fp,
+            _ => panic!("expected field pattern")
+        }
+    }
+
+    pub fn expect_generic_param(self) -> ast::GenericParam {
+        match self {
+            Annotatable::GenericParam(gp) => gp,
+            _ => panic!("expected generic parameter")
+        }
+    }
+
+    pub fn expect_param(self) -> ast::Param {
+        match self {
+            Annotatable::Param(param) => param,
+            _ => panic!("expected parameter")
+        }
+    }
+
+    pub fn expect_struct_field(self) -> ast::StructField {
+        match self {
+            Annotatable::StructField(sf) => sf,
+            _ => panic!("expected struct field")
+        }
+    }
+
+    pub fn expect_variant(self) -> ast::Variant {
+        match self {
+            Annotatable::Variant(v) => v,
+            _ => panic!("expected variant")
+        }
+    }
+
     pub fn derive_allowed(&self) -> bool {
         match *self {
             Annotatable::Item(ref item) => match item.node {
@@ -325,6 +409,34 @@
     fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> {
         None
     }
+
+    fn make_arms(self: Box<Self>) -> Option<SmallVec<[ast::Arm; 1]>> {
+        None
+    }
+
+    fn make_fields(self: Box<Self>) -> Option<SmallVec<[ast::Field; 1]>> {
+        None
+    }
+
+    fn make_field_patterns(self: Box<Self>) -> Option<SmallVec<[ast::FieldPat; 1]>> {
+        None
+    }
+
+    fn make_generic_params(self: Box<Self>) -> Option<SmallVec<[ast::GenericParam; 1]>> {
+        None
+    }
+
+    fn make_params(self: Box<Self>) -> Option<SmallVec<[ast::Param; 1]>> {
+        None
+    }
+
+    fn make_struct_fields(self: Box<Self>) -> Option<SmallVec<[ast::StructField; 1]>> {
+        None
+    }
+
+    fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> {
+        None
+    }
 }
 
 macro_rules! make_MacEager {
@@ -498,6 +610,34 @@
     fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> {
         Some(DummyResult::raw_ty(self.span, self.is_error))
     }
+
+    fn make_arms(self: Box<DummyResult>) -> Option<SmallVec<[ast::Arm; 1]>> {
+       Some(SmallVec::new())
+    }
+
+    fn make_fields(self: Box<DummyResult>) -> Option<SmallVec<[ast::Field; 1]>> {
+        Some(SmallVec::new())
+    }
+
+    fn make_field_patterns(self: Box<DummyResult>) -> Option<SmallVec<[ast::FieldPat; 1]>> {
+        Some(SmallVec::new())
+    }
+
+    fn make_generic_params(self: Box<DummyResult>) -> Option<SmallVec<[ast::GenericParam; 1]>> {
+        Some(SmallVec::new())
+    }
+
+    fn make_params(self: Box<DummyResult>) -> Option<SmallVec<[ast::Param; 1]>> {
+        Some(SmallVec::new())
+    }
+
+    fn make_struct_fields(self: Box<DummyResult>) -> Option<SmallVec<[ast::StructField; 1]>> {
+        Some(SmallVec::new())
+    }
+
+    fn make_variants(self: Box<DummyResult>) -> Option<SmallVec<[ast::Variant; 1]>> {
+        Some(SmallVec::new())
+    }
 }
 
 /// A syntax extension kind.
@@ -837,13 +977,6 @@
         span.with_call_site_ctxt(self.current_expansion.id)
     }
 
-    /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items).
-    /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably),
-    /// or with `with_call_site_ctxt` (where necessary).
-    pub fn with_legacy_ctxt(&self, span: Span) -> Span {
-        span.with_legacy_ctxt(self.current_expansion.id)
-    }
-
     /// Returns span for the macro which originally caused the current expansion to happen.
     ///
     /// Stops backtracing at include! boundary.
@@ -941,8 +1074,8 @@
     pub fn set_trace_macros(&mut self, x: bool) {
         self.ecfg.trace_mac = x
     }
-    pub fn ident_of(&self, st: &str) -> ast::Ident {
-        ast::Ident::from_str(st)
+    pub fn ident_of(&self, st: &str, sp: Span) -> ast::Ident {
+        ast::Ident::from_str_and_span(st, sp)
     }
     pub fn std_path(&self, components: &[Symbol]) -> Vec<ast::Ident> {
         let def_site = self.with_def_site_ctxt(DUMMY_SP);
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index dc6cbfc..f1d0e0b 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -166,7 +166,8 @@
             bounds,
             kind: ast::GenericParamKind::Type {
                 default,
-            }
+            },
+            is_placeholder: false
         }
     }
 
@@ -207,6 +208,7 @@
             attrs: attrs.into(),
             bounds,
             kind: ast::GenericParamKind::Lifetime,
+            is_placeholder: false
         }
     }
 
@@ -361,7 +363,7 @@
         self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp)))
     }
     pub fn expr_tup_field_access(&self, sp: Span, expr: P<ast::Expr>, idx: usize) -> P<ast::Expr> {
-        let ident = Ident::from_str(&idx.to_string()).with_span_pos(sp);
+        let ident = Ident::new(sym::integer(idx), sp);
         self.expr(sp, ast::ExprKind::Field(expr, ident))
     }
     pub fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
@@ -404,6 +406,7 @@
             is_shorthand: false,
             attrs: ThinVec::new(),
             id: ast::DUMMY_NODE_ID,
+            is_placeholder: false,
         }
     }
     pub fn expr_struct(
@@ -522,7 +525,7 @@
         let err = self.std_path(&[sym::result, sym::Result, sym::Err]);
         let err_path = self.path_global(sp, err);
 
-        let binding_variable = self.ident_of("__try_var");
+        let binding_variable = self.ident_of("__try_var", sp);
         let binding_pat = self.pat_ident(sp, binding_variable);
         let binding_expr = self.expr_ident(sp, binding_variable);
 
@@ -614,6 +617,7 @@
             body: expr,
             span,
             id: ast::DUMMY_NODE_ID,
+            is_placeholder: false,
         }
     }
 
@@ -701,6 +705,7 @@
             pat: arg_pat,
             span,
             ty,
+            is_placeholder: false,
         }
     }
 
@@ -774,6 +779,7 @@
                 vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited),
                 attrs: Vec::new(),
                 id: ast::DUMMY_NODE_ID,
+                is_placeholder: false,
             }
         }).collect();
 
@@ -790,6 +796,7 @@
             id: ast::DUMMY_NODE_ID,
             ident,
             span,
+            is_placeholder: false,
         }
     }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 4fd0c36..b80c530 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -26,7 +26,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use std::io::ErrorKind;
-use std::{iter, mem};
+use std::{iter, mem, slice};
 use std::ops::DerefMut;
 use std::rc::Rc;
 use std::path::PathBuf;
@@ -141,7 +141,40 @@
         "impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items;
     }
     ForeignItems(SmallVec<[ast::ForeignItem; 1]>) {
-        "foreign item"; many fn flat_map_foreign_item; fn visit_foreign_item; fn make_foreign_items;
+        "foreign item";
+        many fn flat_map_foreign_item;
+        fn visit_foreign_item;
+        fn make_foreign_items;
+    }
+    Arms(SmallVec<[ast::Arm; 1]>) {
+        "match arm"; many fn flat_map_arm; fn visit_arm; fn make_arms;
+    }
+    Fields(SmallVec<[ast::Field; 1]>) {
+        "field expression"; many fn flat_map_field; fn visit_field; fn make_fields;
+    }
+    FieldPats(SmallVec<[ast::FieldPat; 1]>) {
+        "field pattern";
+        many fn flat_map_field_pattern;
+        fn visit_field_pattern;
+        fn make_field_patterns;
+    }
+    GenericParams(SmallVec<[ast::GenericParam; 1]>) {
+        "generic parameter";
+        many fn flat_map_generic_param;
+        fn visit_generic_param;
+        fn make_generic_params;
+    }
+    Params(SmallVec<[ast::Param; 1]>) {
+        "function parameter"; many fn flat_map_param; fn visit_param; fn make_params;
+    }
+    StructFields(SmallVec<[ast::StructField; 1]>) {
+        "field";
+        many fn flat_map_struct_field;
+        fn visit_struct_field;
+        fn make_struct_fields;
+    }
+    Variants(SmallVec<[ast::Variant; 1]>) {
+        "variant"; many fn flat_map_variant; fn visit_variant; fn make_variants;
     }
 }
 
@@ -154,6 +187,21 @@
                                                                      -> AstFragment {
         let mut items = items.into_iter();
         match self {
+            AstFragmentKind::Arms =>
+                AstFragment::Arms(items.map(Annotatable::expect_arm).collect()),
+            AstFragmentKind::Fields =>
+                AstFragment::Fields(items.map(Annotatable::expect_field).collect()),
+            AstFragmentKind::FieldPats =>
+                AstFragment::FieldPats(items.map(Annotatable::expect_field_pattern).collect()),
+            AstFragmentKind::GenericParams =>
+                AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect()),
+            AstFragmentKind::Params =>
+                AstFragment::Params(items.map(Annotatable::expect_param).collect()),
+            AstFragmentKind::StructFields => AstFragment::StructFields(
+                items.map(Annotatable::expect_struct_field).collect()
+            ),
+            AstFragmentKind::Variants =>
+                AstFragment::Variants(items.map(Annotatable::expect_variant).collect()),
             AstFragmentKind::Items =>
                 AstFragment::Items(items.map(Annotatable::expect_item).collect()),
             AstFragmentKind::ImplItems =>
@@ -177,7 +225,7 @@
 
 pub struct Invocation {
     pub kind: InvocationKind,
-    fragment_kind: AstFragmentKind,
+    pub fragment_kind: AstFragmentKind,
     pub expansion_data: ExpansionData,
 }
 
@@ -482,6 +530,27 @@
             Annotatable::Expr(mut expr) => {
                 Annotatable::Expr({ cfg.visit_expr(&mut expr); expr })
             }
+            Annotatable::Arm(arm) => {
+                Annotatable::Arm(cfg.flat_map_arm(arm).pop().unwrap())
+            }
+            Annotatable::Field(field) => {
+                Annotatable::Field(cfg.flat_map_field(field).pop().unwrap())
+            }
+            Annotatable::FieldPat(fp) => {
+                Annotatable::FieldPat(cfg.flat_map_field_pattern(fp).pop().unwrap())
+            }
+            Annotatable::GenericParam(param) => {
+                Annotatable::GenericParam(cfg.flat_map_generic_param(param).pop().unwrap())
+            }
+            Annotatable::Param(param) => {
+                Annotatable::Param(cfg.flat_map_param(param).pop().unwrap())
+            }
+            Annotatable::StructField(sf) => {
+                Annotatable::StructField(cfg.flat_map_struct_field(sf).pop().unwrap())
+            }
+            Annotatable::Variant(v) => {
+                Annotatable::Variant(cfg.flat_map_variant(v).pop().unwrap())
+            }
         }
     }
 
@@ -547,6 +616,14 @@
                         Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()),
                         Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
                         Annotatable::Expr(expr) => token::NtExpr(expr),
+                        Annotatable::Arm(..)
+                        | Annotatable::Field(..)
+                        | Annotatable::FieldPat(..)
+                        | Annotatable::GenericParam(..)
+                        | Annotatable::Param(..)
+                        | Annotatable::StructField(..)
+                        | Annotatable::Variant(..)
+                            => panic!("unexpected annotatable"),
                     })), DUMMY_SP).into();
                     let input = self.extract_proc_macro_attr_input(attr.tokens, span);
                     let tok_result = expander.expand(self.cx, span, input, item_tok);
@@ -625,6 +702,14 @@
             Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return,
             Annotatable::Stmt(_) => ("statements", sym::proc_macro_hygiene),
             Annotatable::Expr(_) => ("expressions", sym::proc_macro_hygiene),
+            Annotatable::Arm(..)
+            | Annotatable::Field(..)
+            | Annotatable::FieldPat(..)
+            | Annotatable::GenericParam(..)
+            | Annotatable::Param(..)
+            | Annotatable::StructField(..)
+            | Annotatable::Variant(..)
+            => panic!("unexpected annotatable"),
         };
         emit_feature_err(
             self.cx.parse_sess,
@@ -681,6 +766,14 @@
             AstFragmentKind::TraitItems => return,
             AstFragmentKind::ImplItems => return,
             AstFragmentKind::ForeignItems => return,
+            AstFragmentKind::Arms
+            | AstFragmentKind::Fields
+            | AstFragmentKind::FieldPats
+            | AstFragmentKind::GenericParams
+            | AstFragmentKind::Params
+            | AstFragmentKind::StructFields
+            | AstFragmentKind::Variants
+                => panic!("unexpected AST fragment kind"),
         };
         if self.cx.ecfg.proc_macro_hygiene() {
             return
@@ -771,6 +864,14 @@
             },
             AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
             AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
+            AstFragmentKind::Arms
+            | AstFragmentKind::Fields
+            | AstFragmentKind::FieldPats
+            | AstFragmentKind::GenericParams
+            | AstFragmentKind::Params
+            | AstFragmentKind::StructFields
+            | AstFragmentKind::Variants
+                => panic!("unexpected AST fragment kind"),
         })
     }
 
@@ -918,7 +1019,7 @@
     fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
         let features = self.cx.ecfg.features.unwrap();
         for attr in attrs.iter() {
-            self.check_attribute_inner(attr, features);
+            feature_gate::check_attribute(attr, self.cx.parse_sess, features);
 
             // macros are expanded before any lint passes so this warning has to be hardcoded
             if attr.path == sym::derive {
@@ -928,15 +1029,6 @@
             }
         }
     }
-
-    fn check_attribute(&mut self, at: &ast::Attribute) {
-        let features = self.cx.ecfg.features.unwrap();
-        self.check_attribute_inner(at, features);
-    }
-
-    fn check_attribute_inner(&mut self, at: &ast::Attribute, features: &Features) {
-        feature_gate::check_attribute(at, self.cx.parse_sess, features);
-    }
 }
 
 impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
@@ -972,6 +1064,84 @@
         });
     }
 
+    fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
+        let mut arm = configure!(self, arm);
+
+        let (attr, traits, after_derive) = self.classify_item(&mut arm);
+        if attr.is_some() || !traits.is_empty() {
+            return self.collect_attr(attr, traits, Annotatable::Arm(arm),
+                                     AstFragmentKind::Arms, after_derive)
+                                     .make_arms();
+        }
+
+        noop_flat_map_arm(arm, self)
+    }
+
+    fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> {
+        let mut field = configure!(self, field);
+
+        let (attr, traits, after_derive) = self.classify_item(&mut field);
+        if attr.is_some() || !traits.is_empty() {
+            return self.collect_attr(attr, traits, Annotatable::Field(field),
+                                     AstFragmentKind::Fields, after_derive)
+                                     .make_fields();
+        }
+
+        noop_flat_map_field(field, self)
+    }
+
+    fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> {
+        let mut fp = configure!(self, fp);
+
+        let (attr, traits, after_derive) = self.classify_item(&mut fp);
+        if attr.is_some() || !traits.is_empty() {
+            return self.collect_attr(attr, traits, Annotatable::FieldPat(fp),
+                                     AstFragmentKind::FieldPats, after_derive)
+                                     .make_field_patterns();
+        }
+
+        noop_flat_map_field_pattern(fp, self)
+    }
+
+    fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
+        let mut p = configure!(self, p);
+
+        let (attr, traits, after_derive) = self.classify_item(&mut p);
+        if attr.is_some() || !traits.is_empty() {
+            return self.collect_attr(attr, traits, Annotatable::Param(p),
+                                     AstFragmentKind::Params, after_derive)
+                                     .make_params();
+        }
+
+        noop_flat_map_param(p, self)
+    }
+
+    fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> {
+        let mut sf = configure!(self, sf);
+
+        let (attr, traits, after_derive) = self.classify_item(&mut sf);
+        if attr.is_some() || !traits.is_empty() {
+            return self.collect_attr(attr, traits, Annotatable::StructField(sf),
+                                     AstFragmentKind::StructFields, after_derive)
+                                     .make_struct_fields();
+        }
+
+        noop_flat_map_struct_field(sf, self)
+    }
+
+    fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
+        let mut variant = configure!(self, variant);
+
+        let (attr, traits, after_derive) = self.classify_item(&mut variant);
+        if attr.is_some() || !traits.is_empty() {
+            return self.collect_attr(attr, traits, Annotatable::Variant(variant),
+                                     AstFragmentKind::Variants, after_derive)
+                                     .make_variants();
+        }
+
+        noop_flat_map_variant(variant, self)
+    }
+
     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         let expr = configure!(self, expr);
         expr.filter_map(|mut expr| {
@@ -1227,12 +1397,20 @@
         }
     }
 
-   fn flat_map_generic_param(
-       &mut self,
-       param: ast::GenericParam
+    fn flat_map_generic_param(
+        &mut self,
+        param: ast::GenericParam
     ) -> SmallVec<[ast::GenericParam; 1]>
     {
-        let param = configure!(self, param);
+        let mut param = configure!(self, param);
+
+        let (attr, traits, after_derive) = self.classify_item(&mut param);
+        if attr.is_some() || !traits.is_empty() {
+            return self.collect_attr(attr, traits, Annotatable::GenericParam(param),
+                                     AstFragmentKind::GenericParams, after_derive)
+                                     .make_generic_params();
+        }
+
         noop_flat_map_generic_param(param, self)
     }
 
@@ -1258,7 +1436,7 @@
 
                 if let Some(file) = it.value_str() {
                     let err_count = self.cx.parse_sess.span_diagnostic.err_count();
-                    self.check_attribute(&at);
+                    self.check_attributes(slice::from_ref(at));
                     if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
                         // avoid loading the file if they haven't enabled the feature
                         return noop_visit_attribute(at, self);
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index d800cfe..52a0f95 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -32,6 +32,16 @@
         attrs: ThinVec::new(),
         node: ast::ExprKind::Mac(mac_placeholder()),
     });
+    let ty = P(ast::Ty {
+        id,
+        node: ast::TyKind::Mac(mac_placeholder()),
+        span,
+    });
+    let pat = P(ast::Pat {
+        id,
+        node: ast::PatKind::Mac(mac_placeholder()),
+        span,
+    });
 
     match kind {
         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
@@ -67,6 +77,81 @@
             let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ThinVec::new()));
             ast::Stmt { id, span, node: ast::StmtKind::Mac(mac) }
         }]),
+        AstFragmentKind::Arms => AstFragment::Arms(smallvec![
+            ast::Arm {
+                attrs: Default::default(),
+                body: expr_placeholder(),
+                guard: None,
+                id,
+                pat,
+                span,
+                is_placeholder: true,
+            }
+        ]),
+        AstFragmentKind::Fields => AstFragment::Fields(smallvec![
+            ast::Field {
+                attrs: Default::default(),
+                expr: expr_placeholder(),
+                id,
+                ident,
+                is_shorthand: false,
+                span,
+                is_placeholder: true,
+            }
+        ]),
+        AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![
+            ast::FieldPat {
+                attrs: Default::default(),
+                id,
+                ident,
+                is_shorthand: false,
+                pat,
+                span,
+                is_placeholder: true,
+            }
+        ]),
+        AstFragmentKind::GenericParams => AstFragment::GenericParams(smallvec![{
+            ast::GenericParam {
+                attrs: Default::default(),
+                bounds: Default::default(),
+                id,
+                ident,
+                is_placeholder: true,
+                kind: ast::GenericParamKind::Lifetime,
+            }
+        }]),
+        AstFragmentKind::Params => AstFragment::Params(smallvec![
+            ast::Param {
+                attrs: Default::default(),
+                id,
+                pat,
+                span,
+                ty,
+                is_placeholder: true,
+            }
+        ]),
+        AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![
+            ast::StructField {
+                attrs: Default::default(),
+                id,
+                ident: None,
+                span,
+                ty,
+                vis,
+                is_placeholder: true,
+            }
+        ]),
+        AstFragmentKind::Variants => AstFragment::Variants(smallvec![
+            ast::Variant {
+                attrs: Default::default(),
+                data: ast::VariantData::Struct(Default::default(), false),
+                disr_expr: None,
+                id,
+                ident,
+                span,
+                is_placeholder: true,
+            }
+        ])
     }
 }
 
@@ -105,6 +190,66 @@
 }
 
 impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
+    fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
+        if arm.is_placeholder {
+            self.remove(arm.id).make_arms()
+        } else {
+            noop_flat_map_arm(arm, self)
+        }
+    }
+
+    fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> {
+        if field.is_placeholder {
+            self.remove(field.id).make_fields()
+        } else {
+            noop_flat_map_field(field, self)
+        }
+    }
+
+    fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> {
+        if fp.is_placeholder {
+            self.remove(fp.id).make_field_patterns()
+        } else {
+            noop_flat_map_field_pattern(fp, self)
+        }
+    }
+
+    fn flat_map_generic_param(
+        &mut self,
+        param: ast::GenericParam
+    ) -> SmallVec<[ast::GenericParam; 1]>
+    {
+        if param.is_placeholder {
+            self.remove(param.id).make_generic_params()
+        } else {
+            noop_flat_map_generic_param(param, self)
+        }
+    }
+
+    fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
+        if p.is_placeholder {
+            self.remove(p.id).make_params()
+        } else {
+            noop_flat_map_param(p, self)
+        }
+    }
+
+    fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> {
+        if sf.is_placeholder {
+            self.remove(sf.id).make_struct_fields()
+        } else {
+            noop_flat_map_struct_field(sf, self)
+        }
+    }
+
+    fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
+        if variant.is_placeholder {
+            self.remove(variant.id).make_variants()
+        } else {
+            noop_flat_map_variant(variant, self)
+        }
+    }
+
     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         match item.node {
             ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(),
diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax/ext/proc_macro.rs
index 4a44c9a..47b17ce 100644
--- a/src/libsyntax/ext/proc_macro.rs
+++ b/src/libsyntax/ext/proc_macro.rs
@@ -88,6 +88,14 @@
               item: Annotatable)
               -> Vec<Annotatable> {
         let item = match item {
+            Annotatable::Arm(..) |
+            Annotatable::Field(..) |
+            Annotatable::FieldPat(..) |
+            Annotatable::GenericParam(..) |
+            Annotatable::Param(..) |
+            Annotatable::StructField(..) |
+            Annotatable::Variant(..)
+                => panic!("unexpected annotatable"),
             Annotatable::Item(item) => item,
             Annotatable::ImplItem(_) |
             Annotatable::TraitItem(_) |
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 46ffa52..b27e9c5 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -877,9 +877,9 @@
         // Now `last` holds the complete set of NT tokens that could
         // end the sequence before SUFFIX. Check that every one works with `suffix`.
         'each_last: for token in &last.tokens {
-            if let TokenTree::MetaVarDecl(_, ref name, ref frag_spec) = *token {
+            if let TokenTree::MetaVarDecl(_, name, frag_spec) = *token {
                 for next_token in &suffix_first.tokens {
-                    match is_in_follow(next_token, &frag_spec.as_str()) {
+                    match is_in_follow(next_token, frag_spec.name) {
                         IsInFollow::Invalid(msg, help) => {
                             sess.span_diagnostic
                                 .struct_span_err(next_token.span(), &msg)
@@ -948,7 +948,7 @@
 
 fn token_can_be_followed_by_any(tok: &quoted::TokenTree) -> bool {
     if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
-        frag_can_be_followed_by_any(&frag_spec.as_str())
+        frag_can_be_followed_by_any(frag_spec.name)
     } else {
         // (Non NT's can always be followed by anthing in matchers.)
         true
@@ -963,15 +963,15 @@
 /// specifier which consumes at most one token tree can be followed by
 /// a fragment specifier (indeed, these fragments can be followed by
 /// ANYTHING without fear of future compatibility hazards).
-fn frag_can_be_followed_by_any(frag: &str) -> bool {
+fn frag_can_be_followed_by_any(frag: Symbol) -> bool {
     match frag {
-        "item"     | // always terminated by `}` or `;`
-        "block"    | // exactly one token tree
-        "ident"    | // exactly one token tree
-        "literal"  | // exactly one token tree
-        "meta"     | // exactly one token tree
-        "lifetime" | // exactly one token tree
-        "tt" =>   // exactly one token tree
+        sym::item     | // always terminated by `}` or `;`
+        sym::block    | // exactly one token tree
+        sym::ident    | // exactly one token tree
+        sym::literal  | // exactly one token tree
+        sym::meta     | // exactly one token tree
+        sym::lifetime | // exactly one token tree
+        sym::tt =>   // exactly one token tree
             true,
 
         _ =>
@@ -993,7 +993,7 @@
 /// break macros that were relying on that binary operator as a
 /// separator.
 // when changing this do not forget to update doc/book/macros.md!
-fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
+fn is_in_follow(tok: &quoted::TokenTree, frag: Symbol) -> IsInFollow {
     use quoted::TokenTree;
 
     if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
@@ -1002,17 +1002,17 @@
         IsInFollow::Yes
     } else {
         match frag {
-            "item" => {
+            sym::item => {
                 // since items *must* be followed by either a `;` or a `}`, we can
                 // accept anything after them
                 IsInFollow::Yes
             }
-            "block" => {
+            sym::block => {
                 // anything can follow block, the braces provide an easy boundary to
                 // maintain
                 IsInFollow::Yes
             }
-            "stmt" | "expr" => {
+            sym::stmt | sym::expr => {
                 const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
                 match tok {
                     TokenTree::Token(token) => match token.kind {
@@ -1022,7 +1022,7 @@
                     _ => IsInFollow::No(TOKENS),
                 }
             }
-            "pat" => {
+            sym::pat => {
                 const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
                 match tok {
                     TokenTree::Token(token) => match token.kind {
@@ -1033,7 +1033,7 @@
                     _ => IsInFollow::No(TOKENS),
                 }
             }
-            "path" | "ty" => {
+            sym::path | sym::ty => {
                 const TOKENS: &[&str] = &[
                     "`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`",
                     "`where`",
@@ -1061,20 +1061,20 @@
                     _ => IsInFollow::No(TOKENS),
                 }
             }
-            "ident" | "lifetime" => {
+            sym::ident | sym::lifetime => {
                 // being a single token, idents and lifetimes are harmless
                 IsInFollow::Yes
             }
-            "literal" => {
+            sym::literal => {
                 // literals may be of a single token, or two tokens (negative numbers)
                 IsInFollow::Yes
             }
-            "meta" | "tt" => {
+            sym::meta | sym::tt => {
                 // being either a single token or a delimited sequence, tt is
                 // harmless
                 IsInFollow::Yes
             }
-            "vis" => {
+            sym::vis => {
                 // Explicitly disallow `priv`, on the off chance it comes back.
                 const TOKENS: &[&str] = &["`,`", "an ident", "a type"];
                 match tok {
@@ -1099,7 +1099,7 @@
                     _ => IsInFollow::No(TOKENS),
                 }
             }
-            "" => IsInFollow::Yes, // kw::Invalid
+            kw::Invalid => IsInFollow::Yes,
             _ => IsInFollow::Invalid(
                 format!("invalid fragment specifier `{}`", frag),
                 VALID_FRAGMENT_NAMES_MSG,
diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs
index 6c0b271..eff9f90 100644
--- a/src/libsyntax/feature_gate/accepted.rs
+++ b/src/libsyntax/feature_gate/accepted.rs
@@ -241,6 +241,8 @@
     (accepted, underscore_const_names, "1.37.0", Some(54912), None),
     /// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions.
     (accepted, async_await, "1.39.0", Some(50547), None),
+    /// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
+    (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs
index 5a248df..dd78777 100644
--- a/src/libsyntax/feature_gate/active.rs
+++ b/src/libsyntax/feature_gate/active.rs
@@ -461,9 +461,6 @@
     /// Allows non-builtin attributes in inner attribute position.
     (active, custom_inner_attributes, "1.30.0", Some(54726), None),
 
-    /// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
-    (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
-
     /// Allows `impl Trait` in bindings (`let`, `const`, `static`).
     (active, impl_trait_in_bindings, "1.30.0", Some(63065), None),
 
diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs
index 763c3ff..b6e1320 100644
--- a/src/libsyntax/feature_gate/builtin_attrs.rs
+++ b/src/libsyntax/feature_gate/builtin_attrs.rs
@@ -79,6 +79,7 @@
     CrateLevel,
 }
 
+#[derive(Clone, Copy)]
 pub enum AttributeGate {
     /// Is gated by a given feature gate, reason
     /// and function to check if enabled
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index 5711b26..b4491a8 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -1,7 +1,7 @@
 use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState};
 use super::accepted::ACCEPTED_FEATURES;
 use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
-use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
+use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 
 use crate::ast::{
     self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
@@ -32,16 +32,10 @@
     Deprecated(&'static str, Option<&'static str>),
 }
 
-struct Context<'a> {
-    features: &'a Features,
-    parse_sess: &'a ParseSess,
-    plugin_attributes: &'a [(Symbol, AttributeType)],
-}
-
 macro_rules! gate_feature_fn {
     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
         let (cx, has_feature, span,
-             name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
+             name, explain, level) = (&*$cx, $has_feature, $span, $name, $explain, $level);
         let has_feature: bool = has_feature(&$cx.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
         if !has_feature && !span.allows_unstable($name) {
@@ -62,68 +56,8 @@
     };
 }
 
-impl<'a> Context<'a> {
-    fn check_attribute(
-        &self,
-        attr: &ast::Attribute,
-        attr_info: Option<&BuiltinAttribute>,
-        is_macro: bool
-    ) {
-        debug!("check_attribute(attr = {:?})", attr);
-        if let Some(&(name, ty, _template, ref gateage)) = attr_info {
-            if let AttributeGate::Gated(_, name, desc, ref has_feature) = *gateage {
-                if !attr.span.allows_unstable(name) {
-                    gate_feature_fn!(
-                        self, has_feature, attr.span, name, desc, GateStrength::Hard
-                    );
-                }
-            } else if name == sym::doc {
-                if let Some(content) = attr.meta_item_list() {
-                    if content.iter().any(|c| c.check_name(sym::include)) {
-                        gate_feature!(self, external_doc, attr.span,
-                            "`#[doc(include = \"...\")]` is experimental"
-                        );
-                    }
-                }
-            }
-            debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
-            return;
-        } else {
-            for segment in &attr.path.segments {
-                if segment.ident.as_str().starts_with("rustc") {
-                    let msg = "attributes starting with `rustc` are \
-                               reserved for use by the `rustc` compiler";
-                    gate_feature!(self, rustc_attrs, segment.ident.span, msg);
-                }
-            }
-        }
-        for &(n, ty) in self.plugin_attributes {
-            if attr.path == n {
-                // Plugins can't gate attributes, so we don't check for it
-                // unlike the code above; we only use this loop to
-                // short-circuit to avoid the checks below.
-                debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
-                return;
-            }
-        }
-        if !is_macro && !attr::is_known(attr) {
-            // Only run the custom attribute lint during regular feature gate
-            // checking. Macro gating runs before the plugin attributes are
-            // registered, so we skip this in that case.
-            let msg = format!("the attribute `{}` is currently unknown to the compiler and \
-                               may have meaning added to it in the future", attr.path);
-            gate_feature!(self, custom_attribute, attr.span, &msg);
-        }
-    }
-}
-
-pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
-    let cx = Context { features, parse_sess, plugin_attributes: &[] };
-    cx.check_attribute(
-        attr,
-        attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)),
-        true
-    );
+crate fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
+    PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
 }
 
 fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
@@ -238,21 +172,21 @@
     "unsized tuple coercion is not stable enough for use and is subject to change";
 
 struct PostExpansionVisitor<'a> {
-    context: &'a Context<'a>,
-    builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
+    parse_sess: &'a ParseSess,
+    features: &'a Features,
 }
 
 macro_rules! gate_feature_post {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
         let (cx, span) = ($cx, $span);
         if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx.context, $feature, span, $explain)
+            gate_feature!(cx, $feature, span, $explain)
         }
     }};
     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
         let (cx, span) = ($cx, $span);
         if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx.context, $feature, span, $explain, $level)
+            gate_feature!(cx, $feature, span, $explain, $level)
         }
     }}
 }
@@ -316,50 +250,44 @@
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        let attr_info = attr.ident().and_then(|ident| {
-            self.builtin_attributes.get(&ident.name).map(|a| *a)
-        });
-
-        // Check for gated attributes.
-        self.context.check_attribute(attr, attr_info, false);
-
-        if attr.check_name(sym::doc) {
-            if let Some(content) = attr.meta_item_list() {
-                if content.len() == 1 && content[0].check_name(sym::cfg) {
-                    gate_feature_post!(&self, doc_cfg, attr.span,
-                        "`#[doc(cfg(...))]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::masked)) {
-                    gate_feature_post!(&self, doc_masked, attr.span,
-                        "`#[doc(masked)]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::spotlight)) {
-                    gate_feature_post!(&self, doc_spotlight, attr.span,
-                        "`#[doc(spotlight)]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::alias)) {
-                    gate_feature_post!(&self, doc_alias, attr.span,
-                        "`#[doc(alias = \"...\")]` is experimental"
-                    );
-                } else if content.iter().any(|c| c.check_name(sym::keyword)) {
-                    gate_feature_post!(&self, doc_keyword, attr.span,
-                        "`#[doc(keyword = \"...\")]` is experimental"
-                    );
-                }
-            }
+        let attr_info =
+            attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+        // Check feature gates for built-in attributes.
+        if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
+            gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
         }
-
+        // Check input tokens for built-in and key-value attributes.
         match attr_info {
             // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
-            Some(&(name, _, template, _)) if name != sym::rustc_dummy =>
-                check_builtin_attribute(self.context.parse_sess, attr, name, template),
+            Some((name, _, template, _)) if name != sym::rustc_dummy =>
+                check_builtin_attribute(self.parse_sess, attr, name, template),
             _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
                 if token == token::Eq {
                     // All key-value attributes are restricted to meta-item syntax.
-                    attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
+                    attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok();
                 }
             }
         }
+        // Check unstable flavors of the `#[doc]` attribute.
+        if attr.check_name(sym::doc) {
+            for nested_meta in attr.meta_item_list().unwrap_or_default() {
+                macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
+                    $(if nested_meta.check_name(sym::$name) {
+                        let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
+                        gate_feature!(self, $feature, attr.span, msg);
+                    })*
+                }}
+
+                gate_doc!(
+                    include => external_doc
+                    cfg => doc_cfg
+                    masked => doc_masked
+                    spotlight => doc_spotlight
+                    alias => doc_alias
+                    keyword => doc_keyword
+                );
+            }
+        }
     }
 
     fn visit_name(&mut self, sp: Span, name: ast::Name) {
@@ -367,7 +295,7 @@
             gate_feature_post!(
                 &self,
                 non_ascii_idents,
-                self.context.parse_sess.source_map().def_span(sp),
+                self.parse_sess.source_map().def_span(sp),
                 "non-ascii idents are not fully supported"
             );
         }
@@ -423,12 +351,9 @@
                     }
                 }
 
-                let has_feature = self.context.features.arbitrary_enum_discriminant;
+                let has_feature = self.features.arbitrary_enum_discriminant;
                 if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
-                    Parser::maybe_report_invalid_custom_discriminants(
-                        self.context.parse_sess,
-                        &variants,
-                    );
+                    Parser::maybe_report_invalid_custom_discriminants(self.parse_sess, &variants);
                 }
             }
 
@@ -538,7 +463,7 @@
             ast::ExprKind::Type(..) => {
                 // To avoid noise about type ascription in common syntax errors, only emit if it
                 // is the *only* error.
-                if self.context.parse_sess.span_diagnostic.err_count() == 0 {
+                if self.parse_sess.span_diagnostic.err_count() == 0 {
                     gate_feature_post!(&self, type_ascription, e.span,
                                        "type ascription is experimental");
                 }
@@ -872,22 +797,17 @@
 }
 
 pub fn check_crate(krate: &ast::Crate,
-                   sess: &ParseSess,
+                   parse_sess: &ParseSess,
                    features: &Features,
-                   plugin_attributes: &[(Symbol, AttributeType)],
                    unstable: UnstableFeatures) {
-    maybe_stage_features(&sess.span_diagnostic, krate, unstable);
-    let ctx = Context {
-        features,
-        parse_sess: sess,
-        plugin_attributes,
-    };
+    maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
+    let mut visitor = PostExpansionVisitor { parse_sess, features };
 
     macro_rules! gate_all {
         ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); };
         ($spans:ident, $gate:ident, $msg:literal) => {
-            for span in &*sess.gated_spans.$spans.borrow() {
-                gate_feature!(&ctx, $gate, *span, $msg);
+            for span in &*parse_sess.gated_spans.$spans.borrow() {
+                gate_feature!(&visitor, $gate, *span, $msg);
             }
         }
     }
@@ -898,11 +818,7 @@
     gate_all!(yields, generators, "yield syntax is experimental");
     gate_all!(or_patterns, "or-patterns syntax is experimental");
 
-    let visitor = &mut PostExpansionVisitor {
-        context: &ctx,
-        builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,
-    };
-    visit::walk_crate(visitor, krate);
+    visit::walk_crate(&mut visitor, krate);
 }
 
 #[derive(Clone, Copy, Hash)]
diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs
index 1e41667..ca13ab3 100644
--- a/src/libsyntax/feature_gate/mod.rs
+++ b/src/libsyntax/feature_gate/mod.rs
@@ -58,7 +58,8 @@
     deprecated_attributes, is_builtin_attr,  is_builtin_attr_name,
 };
 pub use check::{
-    check_attribute, check_crate, get_features, feature_err, emit_feature_err,
+    check_crate, get_features, feature_err, emit_feature_err,
     Stability, GateIssue, UnstableFeatures,
     EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION,
 };
+crate use check::check_attribute;
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 49efbce..aaf6f3e 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -7,7 +7,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
        test(attr(deny(warnings))))]
 
-#![feature(bind_by_move_pattern_guards)]
+#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
 #![feature(box_syntax)]
 #![feature(const_fn)]
 #![feature(const_transmute)]
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 1c35688..5a37222 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -370,6 +370,7 @@
         attrs,
         id,
         ident,
+        is_placeholder: _,
         is_shorthand: _,
         pat,
         span,
@@ -403,7 +404,7 @@
 }
 
 pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
-    let Arm { attrs, pat, guard, body, span, id } = &mut arm;
+    let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
     visit_attrs(attrs, vis);
     vis.visit_id(id);
     vis.visit_pat(pat);
@@ -477,7 +478,7 @@
 pub fn noop_flat_map_variant<T: MutVisitor>(mut variant: Variant, vis: &mut T)
     -> SmallVec<[Variant; 1]>
 {
-    let Variant { ident, attrs, id, data, disr_expr, span } = &mut variant;
+    let Variant { ident, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
     vis.visit_ident(ident);
     visit_attrs(attrs, vis);
     vis.visit_id(id);
@@ -585,7 +586,7 @@
 }
 
 pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> {
-    let Param { attrs, id, pat, span, ty } = &mut param;
+    let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
     vis.visit_id(id);
     visit_thin_attrs(attrs, vis);
     vis.visit_pat(pat);
@@ -736,7 +737,7 @@
     vis: &mut T
 ) -> SmallVec<[GenericParam; 1]>
 {
-    let GenericParam { id, ident, attrs, bounds, kind } = &mut param;
+    let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param;
     vis.visit_id(id);
     vis.visit_ident(ident);
     visit_thin_attrs(attrs, vis);
@@ -828,7 +829,7 @@
 pub fn noop_flat_map_struct_field<T: MutVisitor>(mut sf: StructField, visitor: &mut T)
     -> SmallVec<[StructField; 1]>
 {
-    let StructField { span, ident, vis, id, ty, attrs } = &mut sf;
+    let StructField { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut sf;
     visitor.visit_span(span);
     visit_opt(ident, |ident| visitor.visit_ident(ident));
     visitor.visit_vis(vis);
@@ -839,7 +840,7 @@
 }
 
 pub fn noop_flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> SmallVec<[Field; 1]> {
-    let Field { ident, expr, span, is_shorthand: _, attrs, id } = &mut f;
+    let Field { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f;
     vis.visit_ident(ident);
     vis.visit_expr(expr);
     vis.visit_id(id);
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index 3120d0e..b74f249 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -29,7 +29,14 @@
         span: ident.span,
         id: ast::DUMMY_NODE_ID
     };
-    Param { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) }
+    Param {
+        attrs: ThinVec::default(),
+        id: ast::DUMMY_NODE_ID,
+        pat,
+        span: ident.span,
+        ty: P(ty),
+        is_placeholder: false,
+    }
 }
 
 pub enum Error {
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index bc1bc00..2441a02 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -13,6 +13,8 @@
 
 use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+#[cfg(target_arch = "x86_64")]
+use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::{Lrc, Lock, Once};
 use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
 use syntax_pos::edition::Edition;
@@ -38,6 +40,11 @@
 
 pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
 
+// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
+// (See also the comment on `DiagnosticBuilderInner`.)
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PResult<'_, bool>, 16);
+
 /// Collected spans during parsing for places where a certain feature was
 /// used and should be feature gated accordingly in `check_crate`.
 #[derive(Default)]
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fcaf506..fcebfa2 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1040,7 +1040,14 @@
 
         let span = lo.to(self.token.span);
 
-        Ok(Param { attrs: attrs.into(), id: DUMMY_NODE_ID, pat, span, ty })
+        Ok(Param {
+            attrs: attrs.into(),
+            id: ast::DUMMY_NODE_ID,
+            is_placeholder: false,
+            pat,
+            span,
+            ty,
+        })
     }
 
     /// Parses mutability (`mut` or nothing).
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index 4dbb5ff..31b2844 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -1193,7 +1193,8 @@
             ty: t,
             pat,
             span,
-            id: DUMMY_NODE_ID
+            id: DUMMY_NODE_ID,
+            is_placeholder: false,
         })
     }
 
@@ -1455,6 +1456,7 @@
             body: expr,
             span: lo.to(hi),
             id: DUMMY_NODE_ID,
+            is_placeholder: false,
         })
     }
 
@@ -1611,6 +1613,7 @@
                         is_shorthand: false,
                         attrs: ThinVec::new(),
                         id: DUMMY_NODE_ID,
+                        is_placeholder: false,
                     });
                 }
             }
@@ -1697,6 +1700,7 @@
             is_shorthand,
             attrs: attrs.into(),
             id: DUMMY_NODE_ID,
+            is_placeholder: false,
         })
     }
 
diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs
index 54f24f8..3e6118a 100644
--- a/src/libsyntax/parse/parser/generics.rs
+++ b/src/libsyntax/parse/parser/generics.rs
@@ -49,7 +49,8 @@
             bounds,
             kind: GenericParamKind::Type {
                 default,
-            }
+            },
+            is_placeholder: false
         })
     }
 
@@ -66,7 +67,8 @@
             bounds: Vec::new(),
             kind: GenericParamKind::Const {
                 ty,
-            }
+            },
+            is_placeholder: false
         })
     }
 
@@ -90,6 +92,7 @@
                     attrs: attrs.into(),
                     bounds,
                     kind: ast::GenericParamKind::Lifetime,
+                    is_placeholder: false
                 });
             } else if self.check_keyword(kw::Const) {
                 // Parse const parameter.
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index be7fc48..cf19664 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -1256,7 +1256,7 @@
             for part in idents {
                 fixed_name.push_str(&format!("_{}", part.name));
             }
-            ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp);
+            ident = Ident::from_str_and_span(&fixed_name, fixed_name_sp);
 
             self.struct_span_err(fixed_name_sp, error_msg)
                 .span_label(fixed_name_sp, "dash-separated idents are not valid")
@@ -1575,6 +1575,7 @@
                 data: struct_def,
                 disr_expr,
                 span: vlo.to(self.prev_span),
+                is_placeholder: false,
             };
             variants.push(vr);
 
@@ -1730,6 +1731,7 @@
                 id: DUMMY_NODE_ID,
                 ty,
                 attrs,
+                is_placeholder: false,
             })
         }).map(|(r, _)| r)
     }
@@ -1821,6 +1823,7 @@
             id: DUMMY_NODE_ID,
             ty,
             attrs,
+            is_placeholder: false,
         })
     }
 
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index 49f8d58..08ee3a6 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -882,6 +882,7 @@
             attrs: attrs.into(),
             id: ast::DUMMY_NODE_ID,
             span: lo.to(hi),
+            is_placeholder: false,
         })
     }
 
diff --git a/src/libsyntax/print/pprust/tests.rs b/src/libsyntax/print/pprust/tests.rs
index afd1726..05d78cd 100644
--- a/src/libsyntax/print/pprust/tests.rs
+++ b/src/libsyntax/print/pprust/tests.rs
@@ -61,6 +61,7 @@
             data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
             disr_expr: None,
             span: syntax_pos::DUMMY_SP,
+            is_placeholder: false,
         };
 
         let varstr = variant_to_string(&var);
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 328b307..75d727b 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -62,7 +62,7 @@
     MacEager::expr(P(ast::Expr {
         id: ast::DUMMY_NODE_ID,
         node: ast::ExprKind::InlineAsm(P(inline_asm)),
-        span: cx.with_legacy_ctxt(sp),
+        span: cx.with_def_site_ctxt(sp),
         attrs: ThinVec::new(),
     }))
 }
diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs
index 001996e..cbfe14f 100644
--- a/src/libsyntax_ext/assert.rs
+++ b/src/libsyntax_ext/assert.rs
@@ -23,7 +23,9 @@
         }
     };
 
-    let sp = cx.with_legacy_ctxt(sp);
+    // `core::panic` and `std::panic` are different macros, so we use call-site
+    // context to pick up whichever is currently in scope.
+    let sp = cx.with_call_site_ctxt(sp);
     let panic_call = Mac {
         path: Path::from_ident(Ident::new(sym::panic, sp)),
         tts: custom_message.unwrap_or_else(|| {
diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs
index 0342e44..3c33baf 100644
--- a/src/libsyntax_ext/cfg.rs
+++ b/src/libsyntax_ext/cfg.rs
@@ -16,7 +16,7 @@
     sp: Span,
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'static> {
-    let sp = cx.with_legacy_ctxt(sp);
+    let sp = cx.with_def_site_ctxt(sp);
 
     match parse_cfg(cx, sp, tts) {
         Ok(cfg) => {
diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs
index fc56dff..16f0160 100644
--- a/src/libsyntax_ext/concat.rs
+++ b/src/libsyntax_ext/concat.rs
@@ -59,6 +59,6 @@
     } else if has_errors {
         return DummyResult::any(sp);
     }
-    let sp = cx.with_legacy_ctxt(sp);
+    let sp = cx.with_def_site_ctxt(sp);
     base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
 }
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index 6391b62..f344706 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -39,7 +39,7 @@
         }
     }
 
-    let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_legacy_ctxt(sp));
+    let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp));
 
     struct ConcatIdentsResult { ident: ast::Ident }
 
diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
index debdc30..13d63aa 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
@@ -109,7 +109,7 @@
         GtOp => "gt",
         GeOp => "ge",
     };
-    cx.expr_method_call(span, lft, ast::Ident::from_str_and_span(op_str, span), vec![rgt])
+    cx.expr_method_call(span, lft, cx.ident_of(op_str, span), vec![rgt])
 }
 
 pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index 781645a..088b61b 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -62,7 +62,7 @@
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
     let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
-    let builder = Ident::from_str_and_span("debug_trait_builder", span);
+    let builder = cx.ident_of("debug_trait_builder", span);
     let builder_expr = cx.expr_ident(span, builder.clone());
 
     let fmt = substr.nonself_args[0].clone();
@@ -72,7 +72,7 @@
         ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
             // tuple struct/"normal" variant
             let expr =
-                cx.expr_method_call(span, fmt, Ident::from_str("debug_tuple"), vec![name]);
+                cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]);
             stmts.push(cx.stmt_let(span, true, builder, expr));
 
             for field in fields {
@@ -93,7 +93,7 @@
         ast::VariantData::Struct(..) => {
             // normal struct/struct variant
             let expr =
-                cx.expr_method_call(span, fmt, Ident::from_str("debug_struct"), vec![name]);
+                cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]);
             stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
 
             for field in fields {
@@ -113,7 +113,7 @@
         }
     }
 
-    let expr = cx.expr_method_call(span, builder_expr, Ident::from_str("finish"), vec![]);
+    let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]);
 
     stmts.push(cx.stmt_expr(expr));
     let block = cx.block(span, stmts);
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
index d3d604b..cde72ab 100644
--- a/src/libsyntax_ext/deriving/decodable.rs
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -66,10 +66,14 @@
                           krate: &str)
                           -> P<Expr> {
     let decoder = substr.nonself_args[0].clone();
-    let recurse = vec![cx.ident_of(krate), cx.ident_of("Decodable"), cx.ident_of("decode")];
+    let recurse = vec![
+        cx.ident_of(krate, trait_span),
+        cx.ident_of("Decodable", trait_span),
+        cx.ident_of("decode", trait_span),
+    ];
     let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
     // throw an underscore in front to suppress unused variable warnings
-    let blkarg = cx.ident_of("_d");
+    let blkarg = cx.ident_of("_d", trait_span);
     let blkdecoder = cx.expr_ident(trait_span, blkarg);
 
     return match *substr.fields {
@@ -78,7 +82,7 @@
                 Unnamed(ref fields, _) => fields.len(),
                 Named(ref fields) => fields.len(),
             };
-            let read_struct_field = cx.ident_of("read_struct_field");
+            let read_struct_field = cx.ident_of("read_struct_field", trait_span);
 
             let path = cx.path_ident(trait_span, substr.type_ident);
             let result =
@@ -94,17 +98,17 @@
             let result = cx.expr_ok(trait_span, result);
             cx.expr_method_call(trait_span,
                                 decoder,
-                                cx.ident_of("read_struct"),
+                                cx.ident_of("read_struct", trait_span),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
                                      cx.expr_usize(trait_span, nfields),
                                      cx.lambda1(trait_span, result, blkarg)])
         }
         StaticEnum(_, ref fields) => {
-            let variant = cx.ident_of("i");
+            let variant = cx.ident_of("i", trait_span);
 
             let mut arms = Vec::with_capacity(fields.len() + 1);
             let mut variants = Vec::with_capacity(fields.len());
-            let rvariant_arg = cx.ident_of("read_enum_variant_arg");
+            let rvariant_arg = cx.ident_of("read_enum_variant_arg", trait_span);
 
             for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
                 variants.push(cx.expr_str(v_span, ident.name));
@@ -132,11 +136,11 @@
             let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
             let result = cx.expr_method_call(trait_span,
                                              blkdecoder,
-                                             cx.ident_of("read_enum_variant"),
+                                             cx.ident_of("read_enum_variant", trait_span),
                                              vec![variant_vec, lambda]);
             cx.expr_method_call(trait_span,
                                 decoder,
-                                cx.ident_of("read_enum"),
+                                cx.ident_of("read_enum", trait_span),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
                                      cx.lambda1(trait_span, result, blkarg)])
         }
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
index 8b18fb2..655d3bb 100644
--- a/src/libsyntax_ext/deriving/encodable.rs
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -153,16 +153,16 @@
                           -> P<Expr> {
     let encoder = substr.nonself_args[0].clone();
     // throw an underscore in front to suppress unused variable warnings
-    let blkarg = cx.ident_of("_e");
+    let blkarg = cx.ident_of("_e", trait_span);
     let blkencoder = cx.expr_ident(trait_span, blkarg);
     let fn_path = cx.expr_path(cx.path_global(trait_span,
-                                              vec![cx.ident_of(krate),
-                                                   cx.ident_of("Encodable"),
-                                                   cx.ident_of("encode")]));
+                                              vec![cx.ident_of(krate, trait_span),
+                                                   cx.ident_of("Encodable", trait_span),
+                                                   cx.ident_of("encode", trait_span)]));
 
     return match *substr.fields {
         Struct(_, ref fields) => {
-            let emit_struct_field = cx.ident_of("emit_struct_field");
+            let emit_struct_field = cx.ident_of("emit_struct_field", trait_span);
             let mut stmts = Vec::new();
             for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
                 let name = match name {
@@ -201,7 +201,7 @@
 
             cx.expr_method_call(trait_span,
                                 encoder,
-                                cx.ident_of("emit_struct"),
+                                cx.ident_of("emit_struct", trait_span),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
                                      cx.expr_usize(trait_span, fields.len()),
                                      blk])
@@ -214,7 +214,7 @@
             // actually exist.
             let me = cx.stmt_let(trait_span, false, blkarg, encoder);
             let encoder = cx.expr_ident(trait_span, blkarg);
-            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
+            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg", trait_span);
             let mut stmts = Vec::new();
             if !fields.is_empty() {
                 let last = fields.len() - 1;
@@ -244,7 +244,7 @@
             let name = cx.expr_str(trait_span, variant.ident.name);
             let call = cx.expr_method_call(trait_span,
                                            blkencoder,
-                                           cx.ident_of("emit_enum_variant"),
+                                           cx.ident_of("emit_enum_variant", trait_span),
                                            vec![name,
                                                 cx.expr_usize(trait_span, idx),
                                                 cx.expr_usize(trait_span, fields.len()),
@@ -252,7 +252,7 @@
             let blk = cx.lambda1(trait_span, call, blkarg);
             let ret = cx.expr_method_call(trait_span,
                                           encoder,
-                                          cx.ident_of("emit_enum"),
+                                          cx.ident_of("emit_enum", trait_span),
                                           vec![cx.expr_str(trait_span ,substr.type_ident.name),
                                                blk]);
             cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 893d89f..aceee62 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -237,7 +237,7 @@
     /// Whether there is a self argument (outer Option) i.e., whether
     /// this is a static function, and whether it is a pointer (inner
     /// Option)
-    pub explicit_self: Option<Option<PtrTy<'a>>>,
+    pub explicit_self: Option<Option<PtrTy>>,
 
     /// Arguments other than the self argument
     pub args: Vec<(Ty<'a>, &'a str)>,
@@ -843,7 +843,7 @@
                                 -> P<Expr> {
         let substructure = Substructure {
             type_ident,
-            method_ident: cx.ident_of(self.name),
+            method_ident: cx.ident_of(self.name, trait_.span),
             self_args,
             nonself_args,
             fields,
@@ -890,7 +890,7 @@
 
         for (ty, name) in self.args.iter() {
             let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
-            let ident = ast::Ident::from_str_and_span(name, trait_.span);
+            let ident = cx.ident_of(name, trait_.span);
             arg_tys.push((ident, ast_ty));
 
             let arg_expr = cx.expr_ident(trait_.span, ident);
@@ -938,7 +938,7 @@
 
         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
 
-        let method_ident = cx.ident_of(self.name);
+        let method_ident = cx.ident_of(self.name, trait_.span);
         let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type));
         let body_block = cx.block_expr(body);
 
@@ -1201,7 +1201,7 @@
             ).collect::<Vec<String>>();
 
         let self_arg_idents = self_arg_names.iter()
-            .map(|name| cx.ident_of(&name[..]))
+            .map(|name| cx.ident_of(name, sp))
             .collect::<Vec<ast::Ident>>();
 
         // The `vi_idents` will be bound, solely in the catch-all, to
@@ -1210,7 +1210,7 @@
         let vi_idents = self_arg_names.iter()
             .map(|name| {
                 let vi_suffix = format!("{}_vi", &name[..]);
-                ast::Ident::from_str_and_span(&vi_suffix[..], trait_.span)
+                cx.ident_of(&vi_suffix[..], trait_.span)
             })
             .collect::<Vec<ast::Ident>>();
 
@@ -1389,7 +1389,7 @@
 
                 let target_ty = cx.ty_ident(
                     sp,
-                    ast::Ident::from_str_and_span(target_type_name, sp),
+                    cx.ident_of(target_type_name, sp),
                 );
                 let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
                 let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
@@ -1591,7 +1591,7 @@
         let mut ident_exprs = Vec::new();
         for (i, struct_field) in struct_def.fields().iter().enumerate() {
             let sp = struct_field.span.with_ctxt(self.span.ctxt());
-            let ident = ast::Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span);
+            let ident = cx.ident_of(&format!("{}_{}", prefix, i), self.span);
             paths.push(ident.with_span_pos(sp));
             let val = cx.expr_path(cx.path_ident(sp, ident));
             let val = if use_temporaries {
@@ -1620,6 +1620,7 @@
                             id: ast::DUMMY_NODE_ID,
                             span: pat.span.with_ctxt(self.span.ctxt()),
                             pat,
+                            is_placeholder: false
                         }
                     })
                     .collect();
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index cb1c7b2..b341a07 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -13,9 +13,9 @@
 
 /// The types of pointers
 #[derive(Clone)]
-pub enum PtrTy<'a> {
+pub enum PtrTy {
     /// &'lifetime mut
-    Borrowed(Option<&'a str>, ast::Mutability),
+    Borrowed(Option<Ident>, ast::Mutability),
     /// *mut
     #[allow(dead_code)]
     Raw(ast::Mutability),
@@ -26,7 +26,7 @@
 #[derive(Clone)]
 pub struct Path<'a> {
     path: Vec<&'a str>,
-    lifetime: Option<&'a str>,
+    lifetime: Option<Ident>,
     params: Vec<Box<Ty<'a>>>,
     kind: PathKind,
 }
@@ -46,7 +46,7 @@
         Path::new_(vec![path], None, Vec::new(), PathKind::Local)
     }
     pub fn new_<'r>(path: Vec<&'r str>,
-                    lifetime: Option<&'r str>,
+                    lifetime: Option<Ident>,
                     params: Vec<Box<Ty<'r>>>,
                     kind: PathKind)
                     -> Path<'r> {
@@ -72,7 +72,7 @@
                    self_ty: Ident,
                    self_generics: &Generics)
                    -> ast::Path {
-        let mut idents = self.path.iter().map(|s| Ident::from_str_and_span(*s, span)).collect();
+        let mut idents = self.path.iter().map(|s| cx.ident_of(*s, span)).collect();
         let lt = mk_lifetimes(cx, span, &self.lifetime);
         let tys: Vec<P<ast::Ty>> =
             self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
@@ -99,7 +99,7 @@
 pub enum Ty<'a> {
     Self_,
     /// &/Box/ Ty
-    Ptr(Box<Ty<'a>>, PtrTy<'a>),
+    Ptr(Box<Ty<'a>>, PtrTy),
     /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
     /// parameter, and things like `i32`
     Literal(Path<'a>),
@@ -107,14 +107,14 @@
     Tuple(Vec<Ty<'a>>),
 }
 
-pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
+pub fn borrowed_ptrty() -> PtrTy {
     Borrowed(None, ast::Mutability::Immutable)
 }
 pub fn borrowed(ty: Box<Ty<'_>>) -> Ty<'_> {
     Ptr(ty, borrowed_ptrty())
 }
 
-pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
+pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
     Some(Some(borrowed_ptrty()))
 }
 
@@ -126,13 +126,11 @@
     Tuple(Vec::new())
 }
 
-fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
-    lt.map(|s|
-        cx.lifetime(span, Ident::from_str(s))
-    )
+fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Option<ast::Lifetime> {
+    lt.map(|ident| cx.lifetime(span, ident))
 }
 
-fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
+fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> {
     mk_lifetime(cx, span, lt).into_iter().collect()
 }
 
@@ -209,7 +207,7 @@
             cx.trait_bound(path)
         })
         .collect();
-    cx.typaram(span, ast::Ident::from_str_and_span(name, span), attrs.to_owned(), bounds, None)
+    cx.typaram(span, cx.ident_of(name, span), attrs.to_owned(), bounds, None)
 }
 
 fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
@@ -265,7 +263,7 @@
 
 pub fn get_explicit_self(cx: &ExtCtxt<'_>,
                          span: Span,
-                         self_ptr: &Option<PtrTy<'_>>)
+                         self_ptr: &Option<PtrTy>)
                          -> (P<Expr>, ast::ExplicitSelf) {
     // this constructs a fresh `self` path
     let self_path = cx.expr_self(span);
@@ -276,7 +274,7 @@
                 respan(span,
                        match *ptr {
                            Borrowed(ref lt, mutbl) => {
-                               let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s)));
+                               let lt = lt.map(|s| cx.lifetime(span, s));
                                SelfKind::Region(lt, mutbl)
                            }
                            Raw(_) => {
diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs
index 179b7fe..70e1fbe 100644
--- a/src/libsyntax_ext/env.rs
+++ b/src/libsyntax_ext/env.rs
@@ -20,16 +20,16 @@
         Some(v) => v,
     };
 
-    let sp = cx.with_legacy_ctxt(sp);
+    let sp = cx.with_def_site_ctxt(sp);
     let e = match env::var(&*var.as_str()) {
         Err(..) => {
-            let lt = cx.lifetime(sp, Ident::with_dummy_span(kw::StaticLifetime));
+            let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
             cx.expr_path(cx.path_all(sp,
                                      true,
                                      cx.std_path(&[sym::option, sym::Option, sym::None]),
                                      vec![GenericArg::Type(cx.ty_rptr(sp,
                                                      cx.ty_ident(sp,
-                                                                 Ident::with_dummy_span(sym::str)),
+                                                                 Ident::new(sym::str, sp)),
                                                      Some(lt),
                                                      ast::Mutability::Immutable))],
                                      vec![]))
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index dec84c8..46c7cbb 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -138,15 +138,23 @@
     }
 
     let fmtstr = p.parse_expr()?;
+    let mut first = true;
     let mut named = false;
 
     while p.token != token::Eof {
         if !p.eat(&token::Comma) {
-            let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
-            err.span_label(p.token.span, "expected `,`");
-            p.maybe_annotate_with_ascription(&mut err, false);
-            return Err(err);
+            if first {
+                // After `format!(""` we always expect *only* a comma...
+                let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+                err.span_label(p.token.span, "expected `,`");
+                p.maybe_annotate_with_ascription(&mut err, false);
+                return Err(err);
+            } else {
+                // ...after that delegate to `expect` to also include the other expected tokens.
+                return Err(p.expect(&token::Comma).err().unwrap());
+            }
         }
+        first = false;
         if p.token == token::Eof {
             break;
         } // accept trailing commas
@@ -478,7 +486,7 @@
         let sp = self.macsp;
         let count = |c, arg| {
             let mut path = Context::rtpath(self.ecx, "Count");
-            path.push(self.ecx.ident_of(c));
+            path.push(self.ecx.ident_of(c, sp));
             match arg {
                 Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
                 None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
@@ -526,7 +534,7 @@
                 let pos = {
                     let pos = |c, arg| {
                         let mut path = Context::rtpath(self.ecx, "Position");
-                        path.push(self.ecx.ident_of(c));
+                        path.push(self.ecx.ident_of(c, sp));
                         match arg {
                             Some(i) => {
                                 let arg = self.ecx.expr_usize(sp, i);
@@ -595,7 +603,7 @@
                 let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
                 let align = |name| {
                     let mut p = Context::rtpath(self.ecx, "Alignment");
-                    p.push(self.ecx.ident_of(name));
+                    p.push(self.ecx.ident_of(name, sp));
                     self.ecx.path_global(sp, p)
                 };
                 let align = match arg.format.align {
@@ -613,11 +621,11 @@
                     sp,
                     path,
                     vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("fill", sp), fill),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("align", sp), align),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("flags", sp), flags),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("precision", sp), prec),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("width", sp), width),
                     ],
                 );
 
@@ -626,8 +634,8 @@
                     sp,
                                           path,
                     vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("position", sp), pos),
+                        self.ecx.field_imm(sp, self.ecx.ident_of("format", sp), fmt),
                     ],
                 ))
             }
@@ -645,7 +653,7 @@
         let mut heads = Vec::with_capacity(self.args.len());
 
         let names_pos: Vec<_> = (0..self.args.len())
-            .map(|i| ast::Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
+            .map(|i| self.ecx.ident_of(&format!("arg{}", i), self.macsp))
             .collect();
 
         // First, build up the static array which will become our precompiled
diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs
index f4af169..19a87e6 100644
--- a/src/libsyntax_ext/global_allocator.rs
+++ b/src/libsyntax_ext/global_allocator.rs
@@ -28,7 +28,7 @@
     };
 
     // Generate a bunch of new items using the AllocFnFactory
-    let span = ecx.with_legacy_ctxt(item.span);
+    let span = ecx.with_def_site_ctxt(item.span);
     let f = AllocFnFactory {
         span,
         kind: AllocatorKind::Global,
@@ -43,7 +43,7 @@
     let const_ty = ecx.ty(span, TyKind::Tup(Vec::new()));
     let const_body = ecx.expr_block(ecx.block(span, stmts));
     let const_item =
-        ecx.item_const(span, Ident::with_dummy_span(kw::Underscore), const_ty, const_body);
+        ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
 
     // Return the original item and the new methods.
     vec![Annotatable::Item(item), Annotatable::Item(const_item)]
@@ -61,7 +61,7 @@
         let mut abi_args = Vec::new();
         let mut i = 0;
         let ref mut mk = || {
-            let name = Ident::from_str(&format!("arg{}", i));
+            let name = self.cx.ident_of(&format!("arg{}", i), self.span);
             i += 1;
             name
         };
@@ -83,7 +83,7 @@
         );
         let item = self.cx.item(
             self.span,
-            Ident::from_str(&self.kind.fn_name(method.name)),
+            self.cx.ident_of(&self.kind.fn_name(method.name), self.span),
             self.attrs(),
             kind,
         );
@@ -119,7 +119,7 @@
     ) -> P<Expr> {
         match *ty {
             AllocatorTy::Layout => {
-                let usize = self.cx.path_ident(self.span, Ident::with_dummy_span(sym::usize));
+                let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span));
                 let ty_usize = self.cx.ty_path(usize);
                 let size = ident();
                 let align = ident();
@@ -177,12 +177,12 @@
     }
 
     fn usize(&self) -> P<Ty> {
-        let usize = self.cx.path_ident(self.span, Ident::with_dummy_span(sym::usize));
+        let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span));
         self.cx.ty_path(usize)
     }
 
     fn ptr_u8(&self) -> P<Ty> {
-        let u8 = self.cx.path_ident(self.span, Ident::with_dummy_span(sym::u8));
+        let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span));
         let ty_u8 = self.cx.ty_path(u8);
         self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
     }
diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs
index 6140f0d..c56b3f3 100644
--- a/src/libsyntax_ext/global_asm.rs
+++ b/src/libsyntax_ext/global_asm.rs
@@ -30,7 +30,7 @@
                 id: ast::DUMMY_NODE_ID,
                 node: ast::ItemKind::GlobalAsm(P(global_asm)),
                 vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited),
-                span: cx.with_legacy_ctxt(sp),
+                span: cx.with_def_site_ctxt(sp),
                 tokens: None,
             })])
         }
diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs
index 31d32d2..a5dcfb9 100644
--- a/src/libsyntax_ext/proc_macro_harness.rs
+++ b/src/libsyntax_ext/proc_macro_harness.rs
@@ -340,12 +340,12 @@
                         Vec::new(),
                         ast::ItemKind::ExternCrate(None));
 
-    let bridge = Ident::from_str_and_span("bridge", span);
-    let client = Ident::from_str_and_span("client", span);
-    let proc_macro_ty = Ident::from_str_and_span("ProcMacro", span);
-    let custom_derive = Ident::from_str_and_span("custom_derive", span);
-    let attr = Ident::from_str_and_span("attr", span);
-    let bang = Ident::from_str_and_span("bang", span);
+    let bridge = cx.ident_of("bridge", span);
+    let client = cx.ident_of("client", span);
+    let proc_macro_ty = cx.ident_of("ProcMacro", span);
+    let custom_derive = cx.ident_of("custom_derive", span);
+    let attr = cx.ident_of("attr", span);
+    let bang = cx.ident_of("bang", span);
 
     let decls = {
         let local_path = |sp: Span, name| {
@@ -378,7 +378,7 @@
 
     let decls_static = cx.item_static(
         span,
-        Ident::from_str_and_span("_DECLS", span),
+        cx.ident_of("_DECLS", span),
         cx.ty_rptr(span,
             cx.ty(span, ast::TyKind::Slice(
                 cx.ty_path(cx.path(span,
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index be5aca7..0910c00 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -98,20 +98,20 @@
 
     // creates test::$name
     let test_path = |name| {
-        cx.path(sp, vec![test_id, cx.ident_of(name)])
+        cx.path(sp, vec![test_id, cx.ident_of(name, sp)])
     };
 
     // creates test::ShouldPanic::$name
     let should_panic_path = |name| {
-        cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic"), cx.ident_of(name)])
+        cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic", sp), cx.ident_of(name, sp)])
     };
 
     // creates $name: $expr
-    let field = |name, expr| cx.field_imm(sp, cx.ident_of(name), expr);
+    let field = |name, expr| cx.field_imm(sp, cx.ident_of(name, sp), expr);
 
     let test_fn = if is_bench {
         // A simple ident for a lambda
-        let b = ast::Ident::from_str_and_span("b", attr_sp);
+        let b = cx.ident_of("b", attr_sp);
 
         cx.expr_call(sp, cx.expr_path(test_path("StaticBenchFn")), vec![
             // |b| self::test::assert_test_result(
diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs
index b93c11f..56de0c9 100644
--- a/src/libsyntax_ext/test_harness.rs
+++ b/src/libsyntax_ext/test_harness.rs
@@ -250,7 +250,7 @@
 
     // test::test_main_static(...)
     let mut test_runner = cx.test_runner.clone().unwrap_or(
-        ecx.path(sp, vec![test_id, Ident::from_str_and_span("test_main_static", sp)]));
+        ecx.path(sp, vec![test_id, ecx.ident_of("test_main_static", sp)]));
 
     test_runner.span = sp;
 
@@ -288,7 +288,7 @@
     // Honor the reexport_test_harness_main attribute
     let main_id = match cx.reexport_test_harness_main {
         Some(sym) => Ident::new(sym, sp.with_ctxt(SyntaxContext::root())),
-        None => Ident::from_str_and_span("main", sp),
+        None => Ident::new(sym::main, sp),
     };
 
     let main = P(ast::Item {
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index f0e7344..8971638 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -677,6 +677,13 @@
         }
     }
 
+    pub fn descr_expected(self) -> &'static str {
+        match self {
+            MacroKind::Attr => "attribute",
+            _ => self.descr(),
+        }
+    }
+
     pub fn article(self) -> &'static str {
         match self {
             MacroKind::Attr => "an",
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 9a296f1..ca177eb 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -526,13 +526,6 @@
         self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
     }
 
-    /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items).
-    /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably),
-    /// or with `with_call_site_ctxt` (where necessary).
-    pub fn with_legacy_ctxt(&self, expn_id: ExpnId) -> Span {
-        self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
-    }
-
     /// Produces a span with the same location as `self` and context produced by a macro with the
     /// given ID and transparency, assuming that macro was defined directly and not produced by
     /// some other macro (which is the case for built-in and procedural macros).
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index ab32d44..597ae83 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -765,7 +765,7 @@
         Ident::with_dummy_span(string.as_symbol())
     }
 
-    /// Maps a string to an identifier with an empty span.
+    /// Maps a string to an identifier with a dummy span.
     pub fn from_str(string: &str) -> Ident {
         Ident::with_dummy_span(Symbol::intern(string))
     }
diff --git a/src/llvm-project b/src/llvm-project
index 48818e9..71fe7ec 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 48818e9f5d0f2d5978a9b43ad1a2e8d0b83f6aa0
+Subproject commit 71fe7ec06b85f612fc0e4eb4134c7a7d0f23fac5
diff --git a/src/test/codegen/adjustments.rs b/src/test/codegen/adjustments.rs
index ae2ff99..ded310d 100644
--- a/src/test/codegen/adjustments.rs
+++ b/src/test/codegen/adjustments.rs
@@ -3,7 +3,7 @@
 #![crate_type = "lib"]
 
 // Hack to get the correct size for the length part in slices
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
diff --git a/src/test/codegen/c-variadic.rs b/src/test/codegen/c-variadic.rs
index bb90a96..2acf95d 100644
--- a/src/test/codegen/c-variadic.rs
+++ b/src/test/codegen/c-variadic.rs
@@ -1,4 +1,5 @@
 // compile-flags: -C no-prepopulate-passes
+// ignore-tidy-linelength
 
 #![crate_type = "lib"]
 #![feature(c_variadic)]
@@ -14,13 +15,13 @@
 #[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_0() {
     // Ensure that we correctly call foreign C-variadic functions.
-    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0)
+    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0)
     foreign_c_variadic_0(0);
-    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42)
+    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42)
     foreign_c_variadic_0(0, 42i32);
-    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024)
+    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
     foreign_c_variadic_0(0, 42i32, 1024i32);
-    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024, i32 0)
+    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
     foreign_c_variadic_0(0, 42i32, 1024i32, 0i32);
 }
 
@@ -34,18 +35,18 @@
 
 #[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) {
-    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 42)
+    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42)
     foreign_c_variadic_1(ap, 42i32);
 }
 #[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) {
-    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42)
+    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42)
     foreign_c_variadic_1(ap, 2i32, 42i32);
 }
 
 #[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) {
-    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42, i32 0)
+    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0)
     foreign_c_variadic_1(ap, 2i32, 42i32, 0i32);
 }
 
@@ -64,12 +65,12 @@
 // Ensure that we generate the correct `call` signature when calling a Rust
 // defined C-variadic.
 pub unsafe fn test_c_variadic_call() {
-    // CHECK: call i32 (i32, ...) @c_variadic(i32 0)
+    // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0)
     c_variadic(0);
-    // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42)
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42)
     c_variadic(0, 42i32);
-    // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024)
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
     c_variadic(0, 42i32, 1024i32);
-    // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024, i32 0)
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
     c_variadic(0, 42i32, 1024i32, 0i32);
 }
diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs
index e152e6e..f67487c 100644
--- a/src/test/codegen/fastcall-inreg.rs
+++ b/src/test/codegen/fastcall-inreg.rs
@@ -49,27 +49,27 @@
 #![crate_type = "lib"]
 
 pub mod tests {
-    // CHECK: @f1(i32 inreg %arg0, i32 inreg %arg1, i32 %arg2)
+    // CHECK: @f1(i32 inreg %_1, i32 inreg %_2, i32 %_3)
     #[no_mangle]
     pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
 
-    // CHECK: @f2(i32* inreg %arg0, i32* inreg %arg1, i32* %arg2)
+    // CHECK: @f2(i32* inreg %_1, i32* inreg %_2, i32* %_3)
     #[no_mangle]
     pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
 
-    // CHECK: @f3(float %arg0, i32 inreg %arg1, i32 inreg %arg2, i32 %arg3)
+    // CHECK: @f3(float %_1, i32 inreg %_2, i32 inreg %_3, i32 %_4)
     #[no_mangle]
     pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
 
-    // CHECK: @f4(i32 inreg %arg0, float %arg1, i32 inreg %arg2, i32 %arg3)
+    // CHECK: @f4(i32 inreg %_1, float %_2, i32 inreg %_3, i32 %_4)
     #[no_mangle]
     pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
 
-    // CHECK: @f5(i64 %arg0, i32 %arg1)
+    // CHECK: @f5(i64 %_1, i32 %_2)
     #[no_mangle]
     pub extern "fastcall" fn f5(_: i64, _: i32) {}
 
-    // CHECK: @f6(i1 inreg zeroext %arg0, i32 inreg %arg1, i32 %arg2)
+    // CHECK: @f6(i1 inreg zeroext %_1, i32 inreg %_2, i32 %_3)
     #[no_mangle]
     pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
 }
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index bd121ef2..7e1791c 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -18,48 +18,48 @@
   x
 }
 
-// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
+// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn readonly_borrow(_: &i32) {
 }
 
-// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
+// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
 // static borrow may be captured
 #[no_mangle]
 pub fn static_borrow(_: &'static i32) {
 }
 
-// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
+// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
 // borrow with named lifetime may be captured
 #[no_mangle]
 pub fn named_borrow<'r>(_: &'r i32) {
 }
 
-// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
+// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %_1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_borrow(_: &UnsafeInner) {
 }
 
-// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
+// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %_1)
 // ... unless this is a mutable borrow, those never alias
 #[no_mangle]
 pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 }
 
-// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %arg0)
+// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_borrow(_: &mut i32) {
 }
 
-// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %arg0)
+// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {
 }
 
-// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %arg0)
+// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn borrowed_struct(_: &S) {
@@ -80,36 +80,36 @@
 }
 
 // Hack to get the correct size for the length part in slices
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
 
-// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn slice(_: &[u8]) {
 }
 
-// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_slice(_: &mut [u8]) {
 }
 
-// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %_1.0, [[USIZE]] %_1.1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_slice(_: &[UnsafeInner]) {
 }
 
-// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow({}* nonnull align 1 %arg0.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %arg0.1)
+// CHECK: @trait_borrow({}* nonnull align 1 %_1.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn trait_borrow(_: &Drop) {
diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs
index 0d3d537..05888c0 100644
--- a/src/test/codegen/personality_lifetimes.rs
+++ b/src/test/codegen/personality_lifetimes.rs
@@ -20,12 +20,13 @@
     let _s = S;
     // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just
     // in the first one.
+    // CHECK: [[SLOT:%[0-9]+]] = alloca { i8*, i32 }
     // CHECK-LABEL: cleanup:
-    // CHECK: bitcast{{.*}}personalityslot
-    // CHECK-NEXT: call void @llvm.lifetime.start
+    // CHECK: [[BITCAST:%[0-9]+]] = bitcast { i8*, i32 }* [[SLOT]] to i8*
+    // CHECK-NEXT: call void @llvm.lifetime.start.{{.*}}({{.*}}, i8* [[BITCAST]])
     // CHECK-LABEL: cleanup1:
-    // CHECK: bitcast{{.*}}personalityslot
-    // CHECK-NEXT: call void @llvm.lifetime.start
+    // CHECK: [[BITCAST1:%[0-9]+]] = bitcast { i8*, i32 }* [[SLOT]] to i8*
+    // CHECK-NEXT: call void @llvm.lifetime.start.{{.*}}({{.*}}, i8* [[BITCAST1]])
     might_unwind();
     let _t = S;
     might_unwind();
diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs
index cbb9942..15f99fd 100644
--- a/src/test/codegen/refs.rs
+++ b/src/test/codegen/refs.rs
@@ -3,7 +3,7 @@
 #![crate_type = "lib"]
 
 // Hack to get the correct size for the length part in slices
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs
index c348a8f..87f29f6 100644
--- a/src/test/codegen/repeat-trusted-len.rs
+++ b/src/test/codegen/repeat-trusted-len.rs
@@ -6,7 +6,7 @@
 
 use std::iter;
 
-// CHECK: @helper([[USIZE:i[0-9]+]] %arg0)
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs
index c9f3837..e705d5c 100644
--- a/src/test/codegen/repr-transparent.rs
+++ b/src/test/codegen/repr-transparent.rs
@@ -14,21 +14,21 @@
 #[repr(transparent)]
 pub struct F32(f32);
 
-// CHECK: define float @test_F32(float %arg0)
+// CHECK: define float @test_F32(float %_1)
 #[no_mangle]
 pub extern fn test_F32(_: F32) -> F32 { loop {} }
 
 #[repr(transparent)]
 pub struct Ptr(*mut u8);
 
-// CHECK: define i8* @test_Ptr(i8* %arg0)
+// CHECK: define i8* @test_Ptr(i8* %_1)
 #[no_mangle]
 pub extern fn test_Ptr(_: Ptr) -> Ptr { loop {} }
 
 #[repr(transparent)]
 pub struct WithZst(u64, Zst1);
 
-// CHECK: define i64 @test_WithZst(i64 %arg0)
+// CHECK: define i64 @test_WithZst(i64 %_1)
 #[no_mangle]
 pub extern fn test_WithZst(_: WithZst) -> WithZst { loop {} }
 
@@ -36,14 +36,14 @@
 pub struct WithZeroSizedArray(*const f32, [i8; 0]);
 
 // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
-// CHECK: define i32* @test_WithZeroSizedArray(i32* %arg0)
+// CHECK: define i32* @test_WithZeroSizedArray(i32* %_1)
 #[no_mangle]
 pub extern fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
 
 #[repr(transparent)]
 pub struct Generic<T>(T);
 
-// CHECK: define double @test_Generic(double %arg0)
+// CHECK: define double @test_Generic(double %_1)
 #[no_mangle]
 pub extern fn test_Generic(_: Generic<f64>) -> Generic<f64> { loop {} }
 
@@ -53,14 +53,14 @@
 #[repr(u8)]
 pub enum Bool { True, False, FileNotFound }
 
-// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %arg0)
+// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %_1)
 #[no_mangle]
 pub extern fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { loop {} }
 
 #[repr(transparent)]
 pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
 
-// CHECK: define i16* @test_LifetimePhantom(i16* %arg0)
+// CHECK: define i16* @test_LifetimePhantom(i16* %_1)
 #[no_mangle]
 pub extern fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> { loop {} }
 
@@ -70,28 +70,28 @@
 
 pub struct Px;
 
-// CHECK: define float @test_UnitPhantom(float %arg0)
+// CHECK: define float @test_UnitPhantom(float %_1)
 #[no_mangle]
 pub extern fn test_UnitPhantom(_: UnitPhantom<f32, Px>) -> UnitPhantom<f32, Px> { loop {} }
 
 #[repr(transparent)]
 pub struct TwoZsts(Zst1, i8, Zst2);
 
-// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %arg0)
+// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %_1)
 #[no_mangle]
 pub extern fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} }
 
 #[repr(transparent)]
 pub struct Nested1(Zst2, Generic<f64>);
 
-// CHECK: define double @test_Nested1(double %arg0)
+// CHECK: define double @test_Nested1(double %_1)
 #[no_mangle]
 pub extern fn test_Nested1(_: Nested1) -> Nested1 { loop {} }
 
 #[repr(transparent)]
 pub struct Nested2(Nested1, Zst1);
 
-// CHECK: define double @test_Nested2(double %arg0)
+// CHECK: define double @test_Nested2(double %_1)
 #[no_mangle]
 pub extern fn test_Nested2(_: Nested2) -> Nested2 { loop {} }
 
@@ -101,7 +101,7 @@
 #[repr(transparent)]
 pub struct Vector(f32x4);
 
-// CHECK: define <4 x float> @test_Vector(<4 x float> %arg0)
+// CHECK: define <4 x float> @test_Vector(<4 x float> %_1)
 #[no_mangle]
 pub extern fn test_Vector(_: Vector) -> Vector { loop {} }
 
@@ -111,7 +111,7 @@
 #[repr(transparent)]
 pub struct StructWithProjection(<f32 as Mirror>::It);
 
-// CHECK: define float @test_Projection(float %arg0)
+// CHECK: define float @test_Projection(float %_1)
 #[no_mangle]
 pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
 
@@ -120,7 +120,7 @@
     Variant(F32)
 }
 
-// CHECK: define float @test_EnumF32(float %arg0)
+// CHECK: define float @test_EnumF32(float %_1)
 #[no_mangle]
 pub extern fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} }
 
@@ -129,7 +129,7 @@
     Variant(Zst1, F32, Zst2)
 }
 
-// CHECK: define float @test_EnumF32WithZsts(float %arg0)
+// CHECK: define float @test_EnumF32WithZsts(float %_1)
 #[no_mangle]
 pub extern fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} }
 
@@ -138,7 +138,7 @@
     field: F32,
 }
 
-// CHECK: define float @test_UnionF32(float %arg0)
+// CHECK: define float @test_UnionF32(float %_1)
 #[no_mangle]
 pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
 
@@ -149,7 +149,7 @@
     zst2: Zst2,
 }
 
-// CHECK: define float @test_UnionF32WithZsts(float %arg0)
+// CHECK: define float @test_UnionF32WithZsts(float %_1)
 #[no_mangle]
 pub extern fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} }
 
diff --git a/src/test/codegen/scalar-pair-bool.rs b/src/test/codegen/scalar-pair-bool.rs
index 78d1025..d91ee7f 100644
--- a/src/test/codegen/scalar-pair-bool.rs
+++ b/src/test/codegen/scalar-pair-bool.rs
@@ -20,24 +20,24 @@
     pair
 }
 
-// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %_1.0, i1 zeroext %_1.1)
 #[no_mangle]
 pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
     // Make sure it can operate directly on the unpacked args
-    // CHECK: and i1 %arg0.0, %arg0.1
-    // CHECK: or i1 %arg0.0, %arg0.1
+    // CHECK: and i1 %_1.0, %_1.1
+    // CHECK: or i1 %_1.0, %_1.1
     (a && b, a || b)
 }
 
-// CHECK: define void @pair_branches(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+// CHECK: define void @pair_branches(i1 zeroext %_1.0, i1 zeroext %_1.1)
 #[no_mangle]
 pub fn pair_branches((a, b): (bool, bool)) {
     // Make sure it can branch directly on the unpacked bool args
-    // CHECK: br i1 %arg0.0
+    // CHECK: br i1 %_1.0
     if a {
         println!("Hello!");
     }
-    // CHECK: br i1 %arg0.1
+    // CHECK: br i1 %_1.1
     if b {
         println!("Goodbye!");
     }
diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs
index b7baffe..7339df1 100644
--- a/src/test/codegen/union-abi.rs
+++ b/src/test/codegen/union-abi.rs
@@ -16,38 +16,38 @@
 #[derive(Copy, Clone)]
 pub union UnionI64x4{ a:(), b: i64x4 }
 
-// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4(_: UnionI64x4) { loop {} }
 
 pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 }
 
-// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} }
 
 pub union UnionI64x4I64{ a: i64x4, b: i64 }
 
-// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} }
 
 pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) }
 
-// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %arg0)
+// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} }
 
 
 pub union UnionF32{a:f32}
 
-// CHECK: define float @test_UnionF32(float %arg0)
+// CHECK: define float @test_UnionF32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
 
 pub union UnionF32F32{a:f32, b:f32}
 
-// CHECK: define float @test_UnionF32F32(float %arg0)
+// CHECK: define float @test_UnionF32F32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} }
 
@@ -58,13 +58,13 @@
 pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} }
 
 pub union UnionU128{a:u128}
-// CHECK: define i128 @test_UnionU128(i128 %arg0)
+// CHECK: define i128 @test_UnionU128(i128 %_1)
 #[no_mangle]
 pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} }
 
 #[repr(C)]
 pub union CUnionU128{a:u128}
-// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %arg0)
+// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %_1)
 #[no_mangle]
 pub fn test_CUnionU128(_: CUnionU128) { loop {} }
 
diff --git a/src/test/ui/issues/issue-44415.rs b/src/test/compile-fail/issue-44415.rs
similarity index 100%
rename from src/test/ui/issues/issue-44415.rs
rename to src/test/compile-fail/issue-44415.rs
diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs
index fef6253..8c86d2c 100644
--- a/src/test/debuginfo/function-arg-initialization.rs
+++ b/src/test/debuginfo/function-arg-initialization.rs
@@ -242,12 +242,12 @@
 
 fn binding(a: i64, b: u64, c: f64) {
     let x = 0; // #break
-    println!("")
+    println!()
 }
 
 fn assignment(mut a: u64, b: u64, c: f64) {
     a = b; // #break
-    println!("")
+    println!()
 }
 
 fn function_call(x: u64, y: u64, z: f64) {
diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs
index 4515e36..9cc2d3b 100644
--- a/src/test/incremental/hashes/function_interfaces.rs
+++ b/src/test/incremental/hashes/function_interfaces.rs
@@ -11,7 +11,6 @@
 
 
 #![allow(warnings)]
-#![feature(intrinsics)]
 #![feature(linkage)]
 #![feature(rustc_attrs)]
 #![crate_type = "rlib"]
@@ -99,17 +98,6 @@
 pub extern "C" fn make_extern() {}
 
 
-// Extern C Extern Rust-Intrinsic ----------------------------------------------
-
-#[cfg(cfail1)]
-pub extern "C" fn make_intrinsic() {}
-
-#[cfg(not(cfail1))]
-#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")]
-#[rustc_clean(cfg = "cfail3")]
-pub extern "rust-intrinsic" fn make_intrinsic() {}
-
-
 // Type Parameter --------------------------------------------------------------
 
 #[cfg(cfail1)]
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 81ff995..3006cdc 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -18,7 +18,6 @@
 #![feature(rustc_attrs)]
 #![crate_type="rlib"]
 #![feature(associated_type_defaults)]
-#![feature(intrinsics)]
 
 
 // Change trait visibility
@@ -318,7 +317,7 @@
 
 
 
-// Change extern "C" to extern "rust-intrinsic"
+// Change extern "C" to extern "stdcall"
 #[cfg(cfail1)]
 trait TraitChangeExternCToRustIntrinsic {
     extern "C" fn method();
@@ -330,7 +329,7 @@
 trait TraitChangeExternCToRustIntrinsic {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    extern "rust-intrinsic" fn method();
+    extern "stdcall" fn method();
 }
 
 
diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs
index 18e0642..c898d3a 100644
--- a/src/test/mir-opt/match-arm-scopes.rs
+++ b/src/test/mir-opt/match-arm-scopes.rs
@@ -8,8 +8,6 @@
 //   all of the bindings for that scope.
 // * No drop flags are used.
 
-#![feature(nll, bind_by_move_pattern_guards)]
-
 fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
     match items {
         (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,
diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs
index 3ef66e2..97a0f4a 100644
--- a/src/test/rustdoc-ui/invalid-syntax.rs
+++ b/src/test/rustdoc-ui/invalid-syntax.rs
@@ -74,3 +74,11 @@
 ///
 /// ```
 pub fn empty_rust_with_whitespace() {}
+
+/// ```
+/// let x = 1;
+/// ```
+///
+///     \____/
+///
+pub fn indent_after_fenced() {}
diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr
index 36209e2..6f50eda 100644
--- a/src/test/rustdoc-ui/invalid-syntax.stderr
+++ b/src/test/rustdoc-ui/invalid-syntax.stderr
@@ -202,6 +202,24 @@
    |     ^^^^^^^
 
 error: unknown start of token: \
+ --> <doctest>:1:1
+  |
+1 | \____/
+  | ^
+
+warning: could not parse code block as Rust code
+  --> $DIR/invalid-syntax.rs:82:9
+   |
+LL | ///     \____/
+   |         ^^^^^^
+
+error: unknown start of token: \
+ --> <rustdoc-highlighting>:1:1
+  |
+1 | \____/
+  | ^
+
+error: unknown start of token: \
  --> <rustdoc-highlighting>:1:1
   |
 1 | \_
diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs
index ea24f58..bd9113c 100644
--- a/src/test/ui-fulldeps/compiler-calls.rs
+++ b/src/test/ui-fulldeps/compiler-calls.rs
@@ -24,7 +24,7 @@
 fn main() {
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
-    rustc_driver::report_ices_to_stderr_if_any(|| {
+    rustc_driver::catch_fatal_errors(|| {
         rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok();
     }).ok();
     assert_eq!(count, 2);
diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.rs b/src/test/ui-fulldeps/hash-stable-is-unstable.rs
index 9f67f64..d79ef62 100644
--- a/src/test/ui-fulldeps/hash-stable-is-unstable.rs
+++ b/src/test/ui-fulldeps/hash-stable-is-unstable.rs
@@ -13,3 +13,5 @@
 #[derive(HashStable)]
 //~^ use of unstable library feature 'rustc_private'
 struct Test;
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr
index 02056d3..e2dc0c3 100644
--- a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr
+++ b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr
@@ -1,7 +1,3 @@
-error[E0601]: `main` function not found in crate `hash_stable_is_unstable`
-   |
-   = note: consider adding a `main` function to `$DIR/hash-stable-is-unstable.rs`
-
 error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
   --> $DIR/hash-stable-is-unstable.rs:3:1
    |
@@ -47,7 +43,6 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/27812
    = help: add `#![feature(rustc_private)]` to the crate attributes to enable
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0601, E0658.
-For more information about an error, try `rustc --explain E0601`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/allocator/hygiene.rs b/src/test/ui/allocator/hygiene.rs
new file mode 100644
index 0000000..9bd8406
--- /dev/null
+++ b/src/test/ui/allocator/hygiene.rs
@@ -0,0 +1,31 @@
+// run-pass
+// no-prefer-dynamic
+// aux-build:custom.rs
+// aux-build:helper.rs
+
+#![allow(nonstandard_style)]
+
+extern crate custom;
+extern crate helper;
+
+use custom::A;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+#[allow(dead_code)]
+struct u8;
+#[allow(dead_code)]
+struct usize;
+#[allow(dead_code)]
+static arg0: () = ();
+
+#[global_allocator]
+pub static GLOBAL: A = A(AtomicUsize::new(0));
+
+fn main() {
+    let n = GLOBAL.0.load(Ordering::SeqCst);
+    let s = Box::new(0);
+    helper::work_with(&s);
+    assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
+    drop(s);
+    assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+}
diff --git a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
index 9db5233..ceca54b 100644
--- a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
+++ b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(associated_type_bounds)]
 
diff --git a/src/test/ui/associated-type-bounds/fn-apit.rs b/src/test/ui/associated-type-bounds/fn-apit.rs
index 7e208b4..3c9f511 100644
--- a/src/test/ui/associated-type-bounds/fn-apit.rs
+++ b/src/test/ui/associated-type-bounds/fn-apit.rs
@@ -1,6 +1,7 @@
 // run-pass
 // aux-build:fn-aux.rs
 
+#![allow(unused)]
 #![feature(associated_type_bounds)]
 
 extern crate fn_aux;
diff --git a/src/test/ui/associated-type-bounds/fn-dyn-apit.rs b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs
index 9ff4a50..c4e8092 100644
--- a/src/test/ui/associated-type-bounds/fn-dyn-apit.rs
+++ b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs
@@ -1,6 +1,7 @@
 // run-pass
 // aux-build:fn-dyn-aux.rs
 
+#![allow(unused)]
 #![feature(associated_type_bounds)]
 
 extern crate fn_dyn_aux;
diff --git a/src/test/ui/associated-type-bounds/fn-inline.rs b/src/test/ui/associated-type-bounds/fn-inline.rs
index 7b18876..8fa7212 100644
--- a/src/test/ui/associated-type-bounds/fn-inline.rs
+++ b/src/test/ui/associated-type-bounds/fn-inline.rs
@@ -1,6 +1,7 @@
 // run-pass
 // aux-build:fn-aux.rs
 
+#![allow(unused)]
 #![feature(associated_type_bounds)]
 
 extern crate fn_aux;
diff --git a/src/test/ui/associated-type-bounds/fn-where.rs b/src/test/ui/associated-type-bounds/fn-where.rs
index 60d7149..9c4f82a 100644
--- a/src/test/ui/associated-type-bounds/fn-where.rs
+++ b/src/test/ui/associated-type-bounds/fn-where.rs
@@ -1,6 +1,7 @@
 // run-pass
 // aux-build:fn-aux.rs
 
+#![allow(unused)]
 #![feature(associated_type_bounds)]
 
 extern crate fn_aux;
diff --git a/src/test/ui/associated-type-bounds/fn-wrap-apit.rs b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs
index 23790d4..96df13e3 100644
--- a/src/test/ui/associated-type-bounds/fn-wrap-apit.rs
+++ b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs
@@ -2,6 +2,7 @@
 // aux-build:fn-aux.rs
 
 #![feature(associated_type_bounds)]
+#![allow(dead_code)]
 
 extern crate fn_aux;
 
diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs
index 83a6082..59ce949 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.rs
+++ b/src/test/ui/associated-type-bounds/inside-adt.rs
@@ -31,3 +31,5 @@
 union U3 { f: dyn Iterator<Item: 'static> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
 //~| ERROR could not find defining uses
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr
index d0e0cec..9c4d03e 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.stderr
+++ b/src/test/ui/associated-type-bounds/inside-adt.stderr
@@ -52,10 +52,6 @@
 LL | union U3 { f: dyn Iterator<Item: 'static> }
    |                            ^^^^^^^^^^^^^
 
-error[E0601]: `main` function not found in crate `inside_adt`
-   |
-   = note: consider adding a `main` function to `$DIR/inside-adt.rs`
-
 error: could not find defining uses
   --> $DIR/inside-adt.rs:5:29
    |
@@ -110,6 +106,5 @@
 LL | union U3 { f: dyn Iterator<Item: 'static> }
    |                            ^^^^^^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: aborting due to 18 previous errors
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/associated-type-bounds/struct-bounds.rs b/src/test/ui/associated-type-bounds/struct-bounds.rs
index 2d189cd..2c1ce1c 100644
--- a/src/test/ui/associated-type-bounds/struct-bounds.rs
+++ b/src/test/ui/associated-type-bounds/struct-bounds.rs
@@ -1,5 +1,6 @@
 // run-pass
 
+#![allow(unused)]
 #![feature(associated_type_bounds)]
 
 trait Tr1 { type As1; }
diff --git a/src/test/ui/async-await/argument-patterns.rs b/src/test/ui/async-await/argument-patterns.rs
index 0e42f48..b9fc1a8 100644
--- a/src/test/ui/async-await/argument-patterns.rs
+++ b/src/test/ui/async-await/argument-patterns.rs
@@ -1,7 +1,6 @@
 // edition:2018
-// run-pass
+// check-pass
 
-#![allow(unused_variables)]
 #![deny(unused_mut)]
 
 type A = Vec<u32>;
diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs
index bf8bf0b..1dc7315 100644
--- a/src/test/ui/async-await/async-await.rs
+++ b/src/test/ui/async-await/async-await.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![allow(unused)]
+
 // edition:2018
 // aux-build:arc_wake.rs
 
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index fad90b2..d2f92f0 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -9,9 +9,9 @@
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
    = note: required because it appears within the type `impl std::fmt::Debug`
-   = note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `{impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
@@ -26,9 +26,9 @@
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
    = note: required because it appears within the type `impl std::fmt::Debug`
-   = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
@@ -45,9 +45,9 @@
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
    = note: required because it appears within the type `std::fmt::Formatter<'_>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
-   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
@@ -68,9 +68,9 @@
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
    = note: required because it appears within the type `std::fmt::Formatter<'_>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
-   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
diff --git a/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs
index 5d020c9..15cc9fb 100644
--- a/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs
+++ b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs
@@ -3,6 +3,9 @@
 // run-pass
 
 #![deny(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+#![allow(path_statements)]
 
 // Test that the drop order for locals in a fn and async fn matches up.
 extern crate arc_wake;
@@ -10,7 +13,6 @@
 use arc_wake::ArcWake;
 use std::cell::RefCell;
 use std::future::Future;
-use std::marker::PhantomData;
 use std::pin::Pin;
 use std::rc::Rc;
 use std::sync::Arc;
@@ -42,7 +44,7 @@
 
 impl Future for NeverReady {
     type Output = ();
-    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
         Poll::Pending
     }
 }
diff --git a/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs
index 84fe793..9e83049 100644
--- a/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs
+++ b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs
@@ -6,6 +6,8 @@
 // parameters (used or unused) are not dropped until the async fn is cancelled.
 // This file is mostly copy-pasted from drop-order-for-async-fn-parameters.rs
 
+#![allow(unused_variables)]
+
 extern crate arc_wake;
 
 use arc_wake::ArcWake;
@@ -43,7 +45,7 @@
 
 impl Future for NeverReady {
     type Output = ();
-    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
         Poll::Pending
     }
 }
diff --git a/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs
new file mode 100644
index 0000000..54059b2
--- /dev/null
+++ b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs
@@ -0,0 +1,19 @@
+// check-pass
+// edition:2018
+
+struct Test(String);
+
+impl Test {
+    async fn borrow_async(&self) {}
+
+    fn with(&mut self, s: &str) -> &mut Self {
+        self.0 = s.into();
+        self
+    }
+}
+
+async fn test() {
+    Test("".to_string()).with("123").borrow_async().await;
+}
+
+fn main() { }
diff --git a/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs
new file mode 100644
index 0000000..c5ea2b8
--- /dev/null
+++ b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs
@@ -0,0 +1,12 @@
+// check-pass
+// edition:2018
+
+async fn foo(x: &[Vec<u32>]) -> u32 {
+    0
+}
+
+async fn bar() {
+    foo(&[vec![123]]).await;
+}
+
+fn main() { }
diff --git a/src/test/ui/async-await/issues/issue-54752-async-block.stderr b/src/test/ui/async-await/issues/issue-54752-async-block.stderr
new file mode 100644
index 0000000..c3b3392
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-54752-async-block.stderr
@@ -0,0 +1,8 @@
+warning: unnecessary parentheses around assigned value
+  --> $DIR/issue-54752-async-block.rs:6:22
+   |
+LL | fn main() { let _a = (async  { }); }
+   |                      ^^^^^^^^^^^^ help: remove these parentheses
+   |
+   = note: `#[warn(unused_parens)]` on by default
+
diff --git a/src/test/ui/async-await/issues/issue-59972.rs b/src/test/ui/async-await/issues/issue-59972.rs
index 154226e..c2e24a9 100644
--- a/src/test/ui/async-await/issues/issue-59972.rs
+++ b/src/test/ui/async-await/issues/issue-59972.rs
@@ -4,7 +4,7 @@
 
 // run-pass
 
-// compile-flags: --edition=2018
+// compile-flags: --edition=2018 -Aunused
 
 pub enum Uninhabited { }
 
diff --git a/src/test/ui/async-await/multiple-lifetimes/hrtb.rs b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs
index 31d0736..e788ca5 100644
--- a/src/test/ui/async-await/multiple-lifetimes/hrtb.rs
+++ b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs
@@ -1,5 +1,5 @@
 // edition:2018
-// run-pass
+// check-pass
 
 // Test that we can use async fns with multiple arbitrary lifetimes.
 
diff --git a/src/test/ui/attributes/item-attributes.rs b/src/test/ui/attributes/item-attributes.rs
index c760a28..79cd0f5 100644
--- a/src/test/ui/attributes/item-attributes.rs
+++ b/src/test/ui/attributes/item-attributes.rs
@@ -11,8 +11,6 @@
 #![rustc_dummy]
 #![rustc_dummy(attr5)]
 
-#![crate_id="foobar#0.1"]
-
 // These are attributes of the following mod
 #[rustc_dummy = "val"]
 #[rustc_dummy = "val"]
diff --git a/src/test/ui/attributes/obsolete-attr.rs b/src/test/ui/attributes/obsolete-attr.rs
index 8759344..42f90ed 100644
--- a/src/test/ui/attributes/obsolete-attr.rs
+++ b/src/test/ui/attributes/obsolete-attr.rs
@@ -1,9 +1,9 @@
-// Obsolete attributes fall back to feature gated custom attributes.
+// Obsolete attributes fall back to unstable custom attributes.
 
 #[ab_isize="stdcall"] extern {}
-//~^ ERROR cannot find attribute macro `ab_isize` in this scope
+//~^ ERROR cannot find attribute `ab_isize` in this scope
 
 #[fixed_stack_segment] fn f() {}
-//~^ ERROR cannot find attribute macro `fixed_stack_segment` in this scope
+//~^ ERROR cannot find attribute `fixed_stack_segment` in this scope
 
 fn main() {}
diff --git a/src/test/ui/attributes/obsolete-attr.stderr b/src/test/ui/attributes/obsolete-attr.stderr
index 9c6909f..2d7c257 100644
--- a/src/test/ui/attributes/obsolete-attr.stderr
+++ b/src/test/ui/attributes/obsolete-attr.stderr
@@ -1,10 +1,10 @@
-error: cannot find attribute macro `fixed_stack_segment` in this scope
+error: cannot find attribute `fixed_stack_segment` in this scope
   --> $DIR/obsolete-attr.rs:6:3
    |
 LL | #[fixed_stack_segment] fn f() {}
    |   ^^^^^^^^^^^^^^^^^^^
 
-error: cannot find attribute macro `ab_isize` in this scope
+error: cannot find attribute `ab_isize` in this scope
   --> $DIR/obsolete-attr.rs:3:3
    |
 LL | #[ab_isize="stdcall"] extern {}
diff --git a/src/test/ui/attributes/unknown-attr.rs b/src/test/ui/attributes/unknown-attr.rs
index 140a1fc..70fef04 100644
--- a/src/test/ui/attributes/unknown-attr.rs
+++ b/src/test/ui/attributes/unknown-attr.rs
@@ -1,12 +1,12 @@
-// Unknown attributes fall back to feature gated custom attributes.
+// Unknown attributes fall back to unstable custom attributes.
 
 #![feature(custom_inner_attributes)]
 
 #![mutable_doc]
-//~^ ERROR cannot find attribute macro `mutable_doc` in this scope
+//~^ ERROR cannot find attribute `mutable_doc` in this scope
 
 #[dance] mod a {}
-//~^ ERROR cannot find attribute macro `dance` in this scope
+//~^ ERROR cannot find attribute `dance` in this scope
 
 #[dance] fn main() {}
-//~^ ERROR cannot find attribute macro `dance` in this scope
+//~^ ERROR cannot find attribute `dance` in this scope
diff --git a/src/test/ui/attributes/unknown-attr.stderr b/src/test/ui/attributes/unknown-attr.stderr
index 4d46387..85c227d 100644
--- a/src/test/ui/attributes/unknown-attr.stderr
+++ b/src/test/ui/attributes/unknown-attr.stderr
@@ -1,16 +1,16 @@
-error: cannot find attribute macro `mutable_doc` in this scope
+error: cannot find attribute `mutable_doc` in this scope
   --> $DIR/unknown-attr.rs:5:4
    |
 LL | #![mutable_doc]
    |    ^^^^^^^^^^^
 
-error: cannot find attribute macro `dance` in this scope
+error: cannot find attribute `dance` in this scope
   --> $DIR/unknown-attr.rs:8:3
    |
 LL | #[dance] mod a {}
    |   ^^^^^
 
-error: cannot find attribute macro `dance` in this scope
+error: cannot find attribute `dance` in this scope
   --> $DIR/unknown-attr.rs:11:3
    |
 LL | #[dance] fn main() {}
diff --git a/src/test/ui/attributes/unnamed-field-attributes.rs b/src/test/ui/attributes/unnamed-field-attributes.rs
new file mode 100644
index 0000000..93f3640
--- /dev/null
+++ b/src/test/ui/attributes/unnamed-field-attributes.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+struct S(
+    #[rustfmt::skip] u8,
+    u16,
+    #[rustfmt::skip] u32,
+);
+
+fn main() {}
diff --git a/src/test/ui/attrs-resolution-errors.rs b/src/test/ui/attrs-resolution-errors.rs
new file mode 100644
index 0000000..a38b3cf
--- /dev/null
+++ b/src/test/ui/attrs-resolution-errors.rs
@@ -0,0 +1,40 @@
+enum FooEnum {
+    #[test]
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    Bar(i32),
+}
+
+struct FooStruct {
+    #[test]
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    bar: i32,
+}
+
+fn main() {
+    let foo_enum_bar = FooEnum::Bar(1);
+    match foo_enum_bar {
+        FooEnum::Bar(x) => {},
+        _ => {}
+    }
+
+    let foo_struct = FooStruct { bar: 1 };
+    match foo_struct {
+        FooStruct {
+            #[test] bar
+            //~^ ERROR expected an inert attribute, found an attribute macro
+        } => {}
+    }
+
+    match 1 {
+        0 => {}
+        #[test]
+        //~^ ERROR expected an inert attribute, found an attribute macro
+        _ => {}
+    }
+
+    let _another_foo_strunct = FooStruct {
+        #[test]
+        //~^ ERROR expected an inert attribute, found an attribute macro
+        bar: 1,
+    };
+}
diff --git a/src/test/ui/attrs-resolution-errors.stderr b/src/test/ui/attrs-resolution-errors.stderr
new file mode 100644
index 0000000..31f2a74
--- /dev/null
+++ b/src/test/ui/attrs-resolution-errors.stderr
@@ -0,0 +1,32 @@
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/attrs-resolution-errors.rs:2:5
+   |
+LL |     #[test]
+   |     ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/attrs-resolution-errors.rs:8:5
+   |
+LL |     #[test]
+   |     ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/attrs-resolution-errors.rs:23:13
+   |
+LL |             #[test] bar
+   |             ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/attrs-resolution-errors.rs:30:9
+   |
+LL |         #[test]
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/attrs-resolution-errors.rs:36:9
+   |
+LL |         #[test]
+   |         ^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/attrs-resolution.rs b/src/test/ui/attrs-resolution.rs
new file mode 100644
index 0000000..6809773
--- /dev/null
+++ b/src/test/ui/attrs-resolution.rs
@@ -0,0 +1,37 @@
+// check-pass
+
+enum FooEnum {
+    #[rustfmt::skip]
+    Bar(i32),
+}
+
+struct FooStruct {
+    #[rustfmt::skip]
+    bar: i32,
+}
+
+fn main() {
+    let foo_enum_bar = FooEnum::Bar(1);
+    match foo_enum_bar {
+        FooEnum::Bar(x) => {}
+        _ => {}
+    }
+
+    let foo_struct = FooStruct { bar: 1 };
+    match foo_struct {
+        FooStruct {
+            #[rustfmt::skip] bar
+        } => {}
+    }
+
+    match 1 {
+        0 => {}
+        #[rustfmt::skip]
+        _ => {}
+    }
+
+    let _another_foo_strunct = FooStruct {
+        #[rustfmt::skip]
+        bar: 1,
+    };
+}
diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr
index f2e0d37..3e36f24 100644
--- a/src/test/ui/auto-ref-slice-plus-ref.stderr
+++ b/src/test/ui/auto-ref-slice-plus-ref.stderr
@@ -12,7 +12,7 @@
   --> $DIR/auto-ref-slice-plus-ref.rs:8:7
    |
 LL |     a.test();
-   |       ^^^^
+   |       ^^^^ method not found in `std::vec::Vec<{integer}>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `test`, perhaps you need to implement it:
@@ -22,7 +22,7 @@
   --> $DIR/auto-ref-slice-plus-ref.rs:10:11
    |
 LL |     ([1]).test();
-   |           ^^^^
+   |           ^^^^ method not found in `[{integer}; 1]`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `test`, perhaps you need to implement it:
@@ -32,7 +32,7 @@
   --> $DIR/auto-ref-slice-plus-ref.rs:11:12
    |
 LL |     (&[1]).test();
-   |            ^^^^
+   |            ^^^^ method not found in `&[{integer}; 1]`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `test`, perhaps you need to implement it:
diff --git a/src/test/ui/bind-by-move/bind-by-move-no-guards.rs b/src/test/ui/bind-by-move/bind-by-move-no-guards.rs
deleted file mode 100644
index bc9b3a8..0000000
--- a/src/test/ui/bind-by-move/bind-by-move-no-guards.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use std::sync::mpsc::channel;
-
-fn main() {
-    let (tx, rx) = channel();
-    let x = Some(rx);
-    tx.send(false);
-    match x {
-        Some(z) if z.recv().unwrap() => { panic!() },
-            //~^ ERROR cannot bind by-move into a pattern guard
-        Some(z) => { assert!(!z.recv().unwrap()); },
-        None => panic!()
-    }
-}
diff --git a/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr b/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr
deleted file mode 100644
index c5f0256..0000000
--- a/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0008]: cannot bind by-move into a pattern guard
-  --> $DIR/bind-by-move-no-guards.rs:8:14
-   |
-LL |         Some(z) if z.recv().unwrap() => { panic!() },
-   |              ^ moves value into pattern guard
-   |
-   = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0008`.
diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.rs b/src/test/ui/borrowck/borrowck-migrate-to-nll.rs
index 98fd568..6587dfd 100644
--- a/src/test/ui/borrowck/borrowck-migrate-to-nll.rs
+++ b/src/test/ui/borrowck/borrowck-migrate-to-nll.rs
@@ -17,7 +17,7 @@
 // revisions: zflag edition
 //[zflag]compile-flags: -Z borrowck=migrate
 //[edition]edition:2018
-//[zflag] run-pass
+//[zflag] check-pass
 
 pub struct Block<'a> {
     current: &'a u8,
diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
index 5b6aa7a..9cbceeb 100644
--- a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
+++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
@@ -8,12 +8,9 @@
     let mut x = Enum::A(&mut n);
     match x {
         Enum::A(_) if { x = Enum::B(false); false } => 1,
-        //~^ ERROR cannot assign in a pattern guard
-        //~| ERROR cannot assign `x` in match guard
+        //~^ ERROR cannot assign `x` in match guard
         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
-        //~^ ERROR cannot mutably borrow in a pattern guard
-        //~| ERROR cannot assign in a pattern guard
-        //~| ERROR cannot mutably borrow `x` in match guard
+        //~^ ERROR cannot mutably borrow `x` in match guard
         Enum::A(p) => *p,
         Enum::B(_) => 2,
     }
diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
index 674f137..6d05e97 100644
--- a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
@@ -1,23 +1,3 @@
-error[E0302]: cannot assign in a pattern guard
-  --> $DIR/borrowck-mutate-in-guard.rs:10:25
-   |
-LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
-   |                         ^^^^^^^^^^^^^^^^^^ assignment in pattern guard
-
-error[E0301]: cannot mutably borrow in a pattern guard
-  --> $DIR/borrowck-mutate-in-guard.rs:13:38
-   |
-LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
-   |                                      ^ borrowed mutably in pattern guard
-   |
-   = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
-
-error[E0302]: cannot assign in a pattern guard
-  --> $DIR/borrowck-mutate-in-guard.rs:13:41
-   |
-LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
-   |                                         ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard
-
 error[E0510]: cannot assign `x` in match guard
   --> $DIR/borrowck-mutate-in-guard.rs:10:25
    |
@@ -27,7 +7,7 @@
    |                         ^^^^^^^^^^^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:13:33
+  --> $DIR/borrowck-mutate-in-guard.rs:12:33
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -35,7 +15,6 @@
 LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
    |                                 ^^^^^^ cannot mutably borrow
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0301, E0302, E0510.
-For more information about an error, try `rustc --explain E0301`.
+For more information about this error, try `rustc --explain E0510`.
diff --git a/src/test/ui/borrowck/issue-10876.rs b/src/test/ui/borrowck/issue-10876.rs
index 20ab905..22eaa11 100644
--- a/src/test/ui/borrowck/issue-10876.rs
+++ b/src/test/ui/borrowck/issue-10876.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 enum Nat {
     S(Box<Nat>),
diff --git a/src/test/ui/borrowck/two-phase-multiple-activations.rs b/src/test/ui/borrowck/two-phase-multiple-activations.rs
index a7fa7fa..599138a 100644
--- a/src/test/ui/borrowck/two-phase-multiple-activations.rs
+++ b/src/test/ui/borrowck/two-phase-multiple-activations.rs
@@ -11,7 +11,7 @@
 }
 
 impl FakeRead for Foo {
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+    fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> Result<usize> {
         Ok(4)
     }
 }
@@ -19,5 +19,5 @@
 fn main() {
     let mut a = Foo {};
     let mut v = Vec::new();
-    a.read_to_end(&mut v);
+    a.read_to_end(&mut v).unwrap();
 }
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
index 4947d6e..ab8398e 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
@@ -37,11 +37,11 @@
   --> $DIR/variadic-ffi-4.rs:20:5
    |
 LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               -------                   ------- has type `core::ffi::VaListImpl<'1>`
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
    |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'2>`
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
 LL |     *ap0 = ap1;
-   |     ^^^^ assignment requires that `'1` must outlive `'2`
+   |     ^^^^ assignment requires that `'2` must outlive `'1`
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:25:5
@@ -57,11 +57,11 @@
   --> $DIR/variadic-ffi-4.rs:25:5
    |
 LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               ---                   ------- has type `core::ffi::VaListImpl<'1>`
+   |                                               ---                   ------- has type `core::ffi::VaListImpl<'2>`
    |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'2>`
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
 LL |     ap0 = &mut ap1;
-   |     ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |     ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
 
 error[E0384]: cannot assign to immutable argument `ap0`
   --> $DIR/variadic-ffi-4.rs:25:5
@@ -99,11 +99,11 @@
   --> $DIR/variadic-ffi-4.rs:33:12
    |
 LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                               -------                   ------- has type `core::ffi::VaListImpl<'1>`
+   |                                               -------                   ------- has type `core::ffi::VaListImpl<'2>`
    |                                               |
-   |                                               has type `&mut core::ffi::VaListImpl<'2>`
+   |                                               has type `&mut core::ffi::VaListImpl<'1>`
 LL |     *ap0 = ap1.clone();
-   |            ^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |            ^^^^^^^^^^^ argument requires that `'2` must outlive `'1`
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/class-cast-to-trait.stderr b/src/test/ui/class-cast-to-trait.stderr
index 39f308c..4cab52e 100644
--- a/src/test/ui/class-cast-to-trait.stderr
+++ b/src/test/ui/class-cast-to-trait.stderr
@@ -2,7 +2,7 @@
   --> $DIR/class-cast-to-trait.rs:53:8
    |
 LL |   nyan.eat();
-   |        ^^^
+   |        ^^^ method not found in `std::boxed::Box<dyn Noisy>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/codemap_tests/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs
index 9f90185..dff2483 100644
--- a/src/test/ui/codemap_tests/bad-format-args.rs
+++ b/src/test/ui/codemap_tests/bad-format-args.rs
@@ -1,5 +1,5 @@
 fn main() {
     format!(); //~ ERROR requires at least a format string argument
     format!("" 1); //~ ERROR expected token: `,`
-    format!("", 1 1); //~ ERROR expected token: `,`
+    format!("", 1 1); //~ ERROR expected one of
 }
diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr
index 5b01314..3372ef6 100644
--- a/src/test/ui/codemap_tests/bad-format-args.stderr
+++ b/src/test/ui/codemap_tests/bad-format-args.stderr
@@ -12,11 +12,11 @@
 LL |     format!("" 1);
    |                ^ expected `,`
 
-error: expected token: `,`
+error: expected one of `,`, `.`, `?`, or an operator, found `1`
   --> $DIR/bad-format-args.rs:4:19
    |
 LL |     format!("", 1 1);
-   |                   ^ expected `,`
+   |                   ^ expected one of `,`, `.`, `?`, or an operator here
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/coherence/coherence_inherent.old.stderr b/src/test/ui/coherence/coherence_inherent.old.stderr
index fa56445..750d243 100644
--- a/src/test/ui/coherence/coherence_inherent.old.stderr
+++ b/src/test/ui/coherence/coherence_inherent.old.stderr
@@ -2,7 +2,7 @@
   --> $DIR/coherence_inherent.rs:35:11
    |
 LL |         s.the_fn();
-   |           ^^^^^^
+   |           ^^^^^^ method not found in `&Lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/coherence/coherence_inherent.re.stderr b/src/test/ui/coherence/coherence_inherent.re.stderr
index fa56445..750d243 100644
--- a/src/test/ui/coherence/coherence_inherent.re.stderr
+++ b/src/test/ui/coherence/coherence_inherent.re.stderr
@@ -2,7 +2,7 @@
   --> $DIR/coherence_inherent.rs:35:11
    |
 LL |         s.the_fn();
-   |           ^^^^^^
+   |           ^^^^^^ method not found in `&Lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/coherence/coherence_inherent_cc.old.stderr b/src/test/ui/coherence/coherence_inherent_cc.old.stderr
index 4d93e69..59166a4 100644
--- a/src/test/ui/coherence/coherence_inherent_cc.old.stderr
+++ b/src/test/ui/coherence/coherence_inherent_cc.old.stderr
@@ -2,7 +2,7 @@
   --> $DIR/coherence_inherent_cc.rs:26:11
    |
 LL |         s.the_fn();
-   |           ^^^^^^
+   |           ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/coherence/coherence_inherent_cc.re.stderr b/src/test/ui/coherence/coherence_inherent_cc.re.stderr
index 4d93e69..59166a4 100644
--- a/src/test/ui/coherence/coherence_inherent_cc.re.stderr
+++ b/src/test/ui/coherence/coherence_inherent_cc.re.stderr
@@ -2,7 +2,7 @@
   --> $DIR/coherence_inherent_cc.rs:26:11
    |
 LL |         s.the_fn();
-   |           ^^^^^^
+   |           ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/coherence/conflicting-impl-with-err.rs b/src/test/ui/coherence/conflicting-impl-with-err.rs
new file mode 100644
index 0000000..3e0234b
--- /dev/null
+++ b/src/test/ui/coherence/conflicting-impl-with-err.rs
@@ -0,0 +1,16 @@
+struct ErrorKind;
+struct Error(ErrorKind);
+
+impl From<nope::Thing> for Error { //~ ERROR failed to resolve
+    fn from(_: nope::Thing) -> Self { //~ ERROR failed to resolve
+        unimplemented!()
+    }
+}
+
+impl From<ErrorKind> for Error {
+    fn from(_: ErrorKind) -> Self {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/conflicting-impl-with-err.stderr b/src/test/ui/coherence/conflicting-impl-with-err.stderr
new file mode 100644
index 0000000..a8a5730
--- /dev/null
+++ b/src/test/ui/coherence/conflicting-impl-with-err.stderr
@@ -0,0 +1,15 @@
+error[E0433]: failed to resolve: use of undeclared type or module `nope`
+  --> $DIR/conflicting-impl-with-err.rs:4:11
+   |
+LL | impl From<nope::Thing> for Error {
+   |           ^^^^ use of undeclared type or module `nope`
+
+error[E0433]: failed to resolve: use of undeclared type or module `nope`
+  --> $DIR/conflicting-impl-with-err.rs:5:16
+   |
+LL |     fn from(_: nope::Thing) -> Self {
+   |                ^^^^ use of undeclared type or module `nope`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/collections-const-new.rs b/src/test/ui/collections-const-new.rs
index e01b0df..a93f9a1 100644
--- a/src/test/ui/collections-const-new.rs
+++ b/src/test/ui/collections-const-new.rs
@@ -1,15 +1,11 @@
-// run-pass
+// check-pass
 
-#![allow(dead_code)]
 // Test several functions can be used for constants
 // 1. Vec::new()
 // 2. String::new()
 
-#![feature(const_vec_new)]
-#![feature(const_string_new)]
-
 const MY_VEC: Vec<usize> = Vec::new();
 
 const MY_STRING: String = String::new();
 
-pub fn main() {}
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-6.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.rs
new file mode 100644
index 0000000..9fa726f
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.rs
@@ -0,0 +1,3 @@
+// compile-flags: --cfg a{
+// error-pattern: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`)
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-6.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.stderr
new file mode 100644
index 0000000..7d2087b
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-6.stderr
@@ -0,0 +1,2 @@
+error: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`)
+
diff --git a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
index db3c7ac..e9df780 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
@@ -1,6 +1,9 @@
 error[E0601]: `main` function not found in crate `cfg_attr_cfg_2`
+  --> $DIR/cfg-attr-cfg-2.rs:8:1
    |
-   = note: consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
+LL | / #[cfg_attr(foo, cfg(bar))]
+LL | | fn main() { }
+   | |_____________^ consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
index 22dbac7..45b757e 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
@@ -1,7 +1,7 @@
 macro_rules! foo {
     () => {
         #[cfg_attr(all(), unknown)]
-        //~^ ERROR cannot find attribute macro `unknown` in this scope
+        //~^ ERROR cannot find attribute `unknown` in this scope
         fn foo() {}
     }
 }
diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
index c7c52a2..ef434ec 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `unknown` in this scope
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27
    |
 LL |         #[cfg_attr(all(), unknown)]
diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.rs b/src/test/ui/conditional-compilation/cfg-generic-params.rs
index d80d3ea..53aa355 100644
--- a/src/test/ui/conditional-compilation/cfg-generic-params.rs
+++ b/src/test/ui/conditional-compilation/cfg-generic-params.rs
@@ -16,21 +16,23 @@
 //~^ ERROR only lifetime parameters can be used in this context
 
 fn f_lt_no<#[cfg_attr(no, unknown)] 'a>() {} // OK
-fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} //~ ERROR attribute `unknown` is currently unknown
+fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {}
+//~^ ERROR cannot find attribute `unknown` in this scope
 fn f_ty_no<#[cfg_attr(no, unknown)] T>() {} // OK
-fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} //~ ERROR attribute `unknown` is currently unknown
+fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {}
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 type FnNo = for<#[cfg_attr(no, unknown)] 'a> fn(); // OK
 type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn();
-//~^ ERROR attribute `unknown` is currently unknown
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK
 type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
-//~^ ERROR attribute `unknown` is currently unknown
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 struct WhereNo where for<#[cfg_attr(no, unknown)] 'a> u8: Copy; // OK
 struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
-//~^ ERROR attribute `unknown` is currently unknown
+//~^ ERROR cannot find attribute `unknown` in this scope
 
 fn main() {
     f_lt::<'static>();
diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.stderr b/src/test/ui/conditional-compilation/cfg-generic-params.stderr
index 1f9731f..d9e29c8 100644
--- a/src/test/ui/conditional-compilation/cfg-generic-params.stderr
+++ b/src/test/ui/conditional-compilation/cfg-generic-params.stderr
@@ -16,51 +16,35 @@
 LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
    |                                                      ^
 
-error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute `unknown` in this scope
+  --> $DIR/cfg-generic-params.rs:34:43
+   |
+LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
+   |                                           ^^^^^^^
+
+error: cannot find attribute `unknown` in this scope
+  --> $DIR/cfg-generic-params.rs:30:40
+   |
+LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
+   |                                        ^^^^^^^
+
+error: cannot find attribute `unknown` in this scope
+  --> $DIR/cfg-generic-params.rs:26:34
+   |
+LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn();
+   |                                  ^^^^^^^
+
+error: cannot find attribute `unknown` in this scope
+  --> $DIR/cfg-generic-params.rs:22:29
+   |
+LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {}
+   |                             ^^^^^^^
+
+error: cannot find attribute `unknown` in this scope
   --> $DIR/cfg-generic-params.rs:19:29
    |
 LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {}
    |                             ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/cfg-generic-params.rs:21:29
-   |
-LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {}
-   |                             ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/cfg-generic-params.rs:24:34
-   |
-LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn();
-   |                                  ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/cfg-generic-params.rs:28:40
-   |
-LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
-   |                                        ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/cfg-generic-params.rs:32:43
-   |
-LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
-   |                                           ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
index c6d42c7..0b5c3e0 100644
--- a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
+++ b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
@@ -1,6 +1,8 @@
 error[E0601]: `main` function not found in crate `cfg_in_crate_1`
+  --> $DIR/cfg-in-crate-1.rs:3:1
    |
-   = note: consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
+LL | #![cfg(bar)]
+   | ^^^^^^^^^^^^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/apit-with-const-param.rs b/src/test/ui/const-generics/apit-with-const-param.rs
index 70e718d..7acc508 100644
--- a/src/test/ui/const-generics/apit-with-const-param.rs
+++ b/src/test/ui/const-generics/apit-with-const-param.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
index d83846f..2d1a405 100644
--- a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
+++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs
@@ -3,6 +3,8 @@
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
+#![allow(dead_code)]
+
 struct ArrayStruct<T, const N: usize> {
     data: [T; N],
 }
diff --git a/src/test/ui/const-generics/const-types.rs b/src/test/ui/const-generics/const-types.rs
index 11757cd..bc51881 100644
--- a/src/test/ui/const-generics/const-types.rs
+++ b/src/test/ui/const-generics/const-types.rs
@@ -3,7 +3,7 @@
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
-#[allow(dead_code)]
+#![allow(dead_code, unused_variables)]
 
 struct ConstArray<T, const LEN: usize> {
     array: [T; LEN],
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.rs b/src/test/ui/const-generics/foreign-item-const-parameter.rs
new file mode 100644
index 0000000..4673c86
--- /dev/null
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.rs
@@ -0,0 +1,10 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+extern "C" {
+    fn foo<const X: usize>(); //~ ERROR foreign items may not have const parameters
+
+    fn bar<T, const X: usize>(_: T); //~ ERROR foreign items may not have type or const parameters
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.stderr b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
new file mode 100644
index 0000000..999feed
--- /dev/null
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
@@ -0,0 +1,27 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/foreign-item-const-parameter.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0044]: foreign items may not have const parameters
+  --> $DIR/foreign-item-const-parameter.rs:5:5
+   |
+LL |     fn foo<const X: usize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
+   |
+   = help: replace the const parameters with concrete consts
+
+error[E0044]: foreign items may not have type or const parameters
+  --> $DIR/foreign-item-const-parameter.rs:7:5
+   |
+LL |     fn bar<T, const X: usize>(_: T);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
+   |
+   = help: replace the type or const parameters with concrete types or consts
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0044`.
diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
index 8f3f916..47b090c 100644
--- a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
+++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
@@ -11,7 +11,7 @@
    | --------- method `f` not found for this
 ...
 LL |     S.f::<0>();
-   |       ^
+   |       ^ method not found in `S`
 
 error[E0107]: wrong number of const arguments: expected 0, found 1
   --> $DIR/invalid-const-arg-for-type-param.rs:8:9
diff --git a/src/test/ui/const-generics/issue-61422.rs b/src/test/ui/const-generics/issue-61422.rs
index 68e5a52..45d37b6 100644
--- a/src/test/ui/const-generics/issue-61422.rs
+++ b/src/test/ui/const-generics/issue-61422.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
@@ -8,7 +8,7 @@
 fn foo<const SIZE: usize>() {
     let arr: [u8; SIZE] = unsafe {
         #[allow(deprecated)]
-        let mut array: [u8; SIZE] = mem::uninitialized();
+        let array: [u8; SIZE] = mem::uninitialized();
         array
     };
 }
diff --git a/src/test/ui/const-generics/unused-const-param.rs b/src/test/ui/const-generics/unused-const-param.rs
index ee98e5e..8025b3a 100644
--- a/src/test/ui/const-generics/unused-const-param.rs
+++ b/src/test/ui/const-generics/unused-const-param.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs
index 4a7d849..f0e1d82 100644
--- a/src/test/ui/consts/const-eval/const_transmute.rs
+++ b/src/test/ui/consts/const-eval/const_transmute.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(const_fn_union)]
+#![allow(dead_code)]
 
 #[repr(C)]
 union Transmute<T: Copy, U: Copy> {
diff --git a/src/test/ui/consts/const-int-overflowing-rpass.rs b/src/test/ui/consts/const-int-overflowing-rpass.rs
index b619c79..9be87a6 100644
--- a/src/test/ui/consts/const-int-overflowing-rpass.rs
+++ b/src/test/ui/consts/const-int-overflowing-rpass.rs
@@ -18,6 +18,10 @@
 const NEG_A: (u32, bool) = 0u32.overflowing_neg();
 const NEG_B: (u32, bool) = core::u32::MAX.overflowing_neg();
 
+const ABS_POS: (i32, bool) = 10i32.overflowing_abs();
+const ABS_NEG: (i32, bool) = (-10i32).overflowing_abs();
+const ABS_MIN: (i32, bool) = i32::min_value().overflowing_abs();
+
 fn main() {
     assert_eq!(ADD_A, (7, false));
     assert_eq!(ADD_B, (0, true));
@@ -36,4 +40,8 @@
 
     assert_eq!(NEG_A, (0, false));
     assert_eq!(NEG_B, (1, true));
+
+    assert_eq!(ABS_POS, (10, false));
+    assert_eq!(ABS_NEG, (10, false));
+    assert_eq!(ABS_MIN, (i32::min_value(), true));
 }
diff --git a/src/test/ui/consts/const-int-sign-rpass.rs b/src/test/ui/consts/const-int-sign-rpass.rs
index 05726cb..dc46fce 100644
--- a/src/test/ui/consts/const-int-sign-rpass.rs
+++ b/src/test/ui/consts/const-int-sign-rpass.rs
@@ -11,6 +11,9 @@
 const SIGNUM_NIL: i32 = 0i32.signum();
 const SIGNUM_NEG: i32 = (-42i32).signum();
 
+const ABS_A: i32 = 10i32.abs();
+const ABS_B: i32 = (-10i32).abs();
+
 fn main() {
     assert!(NEGATIVE_A);
     assert!(!NEGATIVE_B);
@@ -20,4 +23,7 @@
     assert_eq!(SIGNUM_POS, 1);
     assert_eq!(SIGNUM_NIL, 0);
     assert_eq!(SIGNUM_NEG, -1);
+
+    assert_eq!(ABS_A, 10);
+    assert_eq!(ABS_B, 10);
 }
diff --git a/src/test/ui/consts/const-int-wrapping-rpass.rs b/src/test/ui/consts/const-int-wrapping-rpass.rs
index 73147d7..2bbad99 100644
--- a/src/test/ui/consts/const-int-wrapping-rpass.rs
+++ b/src/test/ui/consts/const-int-wrapping-rpass.rs
@@ -18,6 +18,10 @@
 const NEG_A: u32 = 5u32.wrapping_neg();
 const NEG_B: u32 = 1234567890u32.wrapping_neg();
 
+const ABS_POS: i32 = 10i32.wrapping_abs();
+const ABS_NEG: i32 = (-10i32).wrapping_abs();
+const ABS_MIN: i32 = i32::min_value().wrapping_abs();
+
 fn main() {
     assert_eq!(ADD_A, 255);
     assert_eq!(ADD_B, 199);
@@ -36,4 +40,8 @@
 
     assert_eq!(NEG_A, 4294967291);
     assert_eq!(NEG_B, 3060399406);
+
+    assert_eq!(ABS_POS, 10);
+    assert_eq!(ABS_NEG, 10);
+    assert_eq!(ABS_MIN, i32::min_value());
 }
diff --git a/src/test/ui/consts/const-labeled-break.rs b/src/test/ui/consts/const-labeled-break.rs
index 36e308a..7cdbb22 100644
--- a/src/test/ui/consts/const-labeled-break.rs
+++ b/src/test/ui/consts/const-labeled-break.rs
@@ -1,4 +1,4 @@
-// run-pass
+// build-pass
 
 // Using labeled break in a while loop has caused an illegal instruction being
 // generated, and an ICE later.
diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr
index 3bcb50c..24d2e3c 100644
--- a/src/test/ui/consts/const-match-check.eval1.stderr
+++ b/src/test/ui/consts/const-match-check.eval1.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
+error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
   --> $DIR/const-match-check.rs:25:15
    |
 LL |     A = { let 0 = 0; 0 },
-   |               ^ pattern `std::i32::MIN..=-1i32` not covered
+   |               ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr
index e292e1c..5d59d06 100644
--- a/src/test/ui/consts/const-match-check.eval2.stderr
+++ b/src/test/ui/consts/const-match-check.eval2.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
+error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
   --> $DIR/const-match-check.rs:31:24
    |
 LL |     let x: [i32; { let 0 = 0; 0 }] = [];
-   |                        ^ pattern `std::i32::MIN..=-1i32` not covered
+   |                        ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr
index 8a9fbde..6d74c26 100644
--- a/src/test/ui/consts/const-match-check.matchck.stderr
+++ b/src/test/ui/consts/const-match-check.matchck.stderr
@@ -1,26 +1,26 @@
-error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
+error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
   --> $DIR/const-match-check.rs:4:22
    |
 LL | const X: i32 = { let 0 = 0; 0 };
-   |                      ^ pattern `std::i32::MIN..=-1i32` not covered
+   |                      ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
 
-error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
+error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
   --> $DIR/const-match-check.rs:8:23
    |
 LL | static Y: i32 = { let 0 = 0; 0 };
-   |                       ^ pattern `std::i32::MIN..=-1i32` not covered
+   |                       ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
 
-error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
+error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
   --> $DIR/const-match-check.rs:13:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
-   |                          ^ pattern `std::i32::MIN..=-1i32` not covered
+   |                          ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
 
-error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
+error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
   --> $DIR/const-match-check.rs:19:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
-   |                          ^ pattern `std::i32::MIN..=-1i32` not covered
+   |                          ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const-pattern-irrefutable.rs b/src/test/ui/consts/const-pattern-irrefutable.rs
index d3f7be1..60e16aa 100644
--- a/src/test/ui/consts/const-pattern-irrefutable.rs
+++ b/src/test/ui/consts/const-pattern-irrefutable.rs
@@ -9,8 +9,8 @@
 const a: u8 = 2;
 
 fn main() {
-    let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
-    let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
-    let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
+    let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX
+    let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX
+    let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
diff --git a/src/test/ui/consts/const-pattern-irrefutable.stderr b/src/test/ui/consts/const-pattern-irrefutable.stderr
index 48fe24d..06f5e90 100644
--- a/src/test/ui/consts/const-pattern-irrefutable.stderr
+++ b/src/test/ui/consts/const-pattern-irrefutable.stderr
@@ -1,16 +1,16 @@
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
+error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:12:9
    |
 LL |     let a = 4;
    |         ^ interpreted as a constant pattern, not new variable
 
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
+error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:13:9
    |
 LL |     let c = 4;
    |         ^ interpreted as a constant pattern, not new variable
 
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
+error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:14:9
    |
 LL |     let d = 4;
diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr
index fdba359..1ae39e7 100644
--- a/src/test/ui/consts/const-size_of-cycle.stderr
+++ b/src/test/ui/consts/const-size_of-cycle.stderr
@@ -14,6 +14,11 @@
    |
 LL |     intrinsics::size_of::<T>()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `std::intrinsics::size_of`...
+  --> $SRC_DIR/libcore/intrinsics.rs:LL:COL
+   |
+LL |     pub fn size_of<T>() -> usize;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Foo`...
    = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
    = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
diff --git a/src/test/ui/consts/const_let_refutable.stderr b/src/test/ui/consts/const_let_refutable.stderr
index 31a3098..7f15f02 100644
--- a/src/test/ui/consts/const_let_refutable.stderr
+++ b/src/test/ui/consts/const_let_refutable.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in function argument: `&[]` not covered
+error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _]` not covered
   --> $DIR/const_let_refutable.rs:3:16
    |
 LL | const fn slice([a, b]: &[i32]) -> i32 {
-   |                ^^^^^^ pattern `&[]` not covered
+   |                ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _]` not covered
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
   --> $DIR/const_let_refutable.rs:4:5
diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr
index 158581f..bf0bd3a 100644
--- a/src/test/ui/consts/match_ice.stderr
+++ b/src/test/ui/consts/match_ice.stderr
@@ -7,6 +7,9 @@
 error[E0004]: non-exhaustive patterns: `&T` not covered
   --> $DIR/match_ice.rs:15:11
    |
+LL | struct T;
+   | --------- `T` defined here
+...
 LL |     match K {
    |           ^ pattern `&T` not covered
    |
diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
index 5fb9253..8b17f68 100644
--- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
+++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
@@ -14,8 +14,9 @@
 impl Foo<u32> for () {
     const X: u32 = 42;
 }
+
 impl Foo<Vec<u32>> for String {
-    const X: Vec<u32> = Vec::new(); //~ ERROR not yet stable as a const fn
+    const X: Vec<u32> = Vec::new();
 }
 
 impl Bar<u32, ()> for () {}
diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
index c56ebf6..5bc7b70 100644
--- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
+++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
@@ -4,13 +4,5 @@
 LL |     const F: u32 = (U::X, 42).1;
    |                    ^^^^^^^^^^ constants cannot evaluate destructors
 
-error: `std::vec::Vec::<T>::new` is not yet stable as a const fn
-  --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:18:25
-   |
-LL |     const X: Vec<u32> = Vec::new();
-   |                         ^^^^^^^^^^
-   |
-   = help: add `#![feature(const_vec_new)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs
new file mode 100644
index 0000000..b476e04
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs
@@ -0,0 +1,20 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+
+#![feature(const_raw_ptr_deref)]
+#![deny(const_err)]
+
+use std::cell::UnsafeCell;
+
+// make sure we do not just intern this as mutable
+const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+
+const MUTATING_BEHIND_RAW: () = {
+    // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
+    unsafe {
+        *MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks
+        //~^ ERROR any use of this value will cause an error
+        //~^^ tried to modify constant memory
+    }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr
new file mode 100644
index 0000000..507d4823
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr
@@ -0,0 +1,27 @@
+warning: skipping const checks
+  --> $DIR/mutable_const.rs:14:9
+   |
+LL |         *MUTABLE_BEHIND_RAW = 99
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: any use of this value will cause an error
+  --> $DIR/mutable_const.rs:14:9
+   |
+LL | / const MUTATING_BEHIND_RAW: () = {
+LL | |     // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
+LL | |     unsafe {
+LL | |         *MUTABLE_BEHIND_RAW = 99
+   | |         ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory
+...  |
+LL | |     }
+LL | | };
+   | |__-
+   |
+note: lint level defined here
+  --> $DIR/mutable_const.rs:4:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr
index 82569e2..28cf353 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr
@@ -6,7 +6,7 @@
 
 thread 'rustc' panicked at 'assertion failed: `(left != right)`
   left: `Const`,
- right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites may arbitrarily decide to change, too.', src/librustc_mir/interpret/intern.rs:LL:CC
+ right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites could observe that mutation.', src/librustc_mir/interpret/intern.rs:LL:CC
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 error: internal compiler error: unexpected panic
diff --git a/src/test/ui/consts/packed_pattern.stderr b/src/test/ui/consts/packed_pattern.stderr
new file mode 100644
index 0000000..9b7daf2
--- /dev/null
+++ b/src/test/ui/consts/packed_pattern.stderr
@@ -0,0 +1,8 @@
+warning: unreachable pattern
+  --> $DIR/packed_pattern.rs:16:9
+   |
+LL |         FOO => unreachable!(),
+   |         ^^^
+   |
+   = note: `#[warn(unreachable_patterns)]` on by default
+
diff --git a/src/test/ui/consts/packed_pattern2.stderr b/src/test/ui/consts/packed_pattern2.stderr
new file mode 100644
index 0000000..6cc0225
--- /dev/null
+++ b/src/test/ui/consts/packed_pattern2.stderr
@@ -0,0 +1,8 @@
+warning: unreachable pattern
+  --> $DIR/packed_pattern2.rs:24:9
+   |
+LL |         FOO => unreachable!(),
+   |         ^^^
+   |
+   = note: `#[warn(unreachable_patterns)]` on by default
+
diff --git a/src/test/ui/continue-after-missing-main.nll.stderr b/src/test/ui/continue-after-missing-main.nll.stderr
index aceabf3..b94c365 100644
--- a/src/test/ui/continue-after-missing-main.nll.stderr
+++ b/src/test/ui/continue-after-missing-main.nll.stderr
@@ -1,6 +1,14 @@
 error[E0601]: `main` function not found in crate `continue_after_missing_main`
+  --> $DIR/continue-after-missing-main.rs:1:1
    |
-   = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+LL | / #![allow(dead_code)]
+LL | |
+LL | | // error-pattern:`main` function not found in crate
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/continue-after-missing-main.stderr b/src/test/ui/continue-after-missing-main.stderr
index cc5f876..d764e7d 100644
--- a/src/test/ui/continue-after-missing-main.stderr
+++ b/src/test/ui/continue-after-missing-main.stderr
@@ -1,6 +1,14 @@
 error[E0601]: `main` function not found in crate `continue_after_missing_main`
+  --> $DIR/continue-after-missing-main.rs:1:1
    |
-   = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+LL | / #![allow(dead_code)]
+LL | |
+LL | | // error-pattern:`main` function not found in crate
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
 
 error[E0623]: lifetime mismatch
   --> $DIR/continue-after-missing-main.rs:30:56
diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr
index cceb9e3..054bd09 100644
--- a/src/test/ui/copy-a-resource.stderr
+++ b/src/test/ui/copy-a-resource.stderr
@@ -5,7 +5,7 @@
    | ---------- method `clone` not found for this
 ...
 LL |     let _y = x.clone();
-   |                ^^^^^
+   |                ^^^^^ method not found in `Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
diff --git a/src/test/ui/custom_attribute.rs b/src/test/ui/custom_attribute.rs
index 13c873c..4957184 100644
--- a/src/test/ui/custom_attribute.rs
+++ b/src/test/ui/custom_attribute.rs
@@ -1,9 +1,9 @@
 #![feature(stmt_expr_attributes)]
 
-#[foo] //~ ERROR cannot find attribute macro `foo` in this scope
+#[foo] //~ ERROR cannot find attribute `foo` in this scope
 fn main() {
-    #[foo] //~ ERROR cannot find attribute macro `foo` in this scope
+    #[foo] //~ ERROR cannot find attribute `foo` in this scope
     let x = ();
-    #[foo] //~ ERROR cannot find attribute macro `foo` in this scope
+    #[foo] //~ ERROR cannot find attribute `foo` in this scope
     x
 }
diff --git a/src/test/ui/custom_attribute.stderr b/src/test/ui/custom_attribute.stderr
index b4f9f3f..4023892 100644
--- a/src/test/ui/custom_attribute.stderr
+++ b/src/test/ui/custom_attribute.stderr
@@ -1,16 +1,16 @@
-error: cannot find attribute macro `foo` in this scope
+error: cannot find attribute `foo` in this scope
   --> $DIR/custom_attribute.rs:3:3
    |
 LL | #[foo]
    |   ^^^
 
-error: cannot find attribute macro `foo` in this scope
+error: cannot find attribute `foo` in this scope
   --> $DIR/custom_attribute.rs:5:7
    |
 LL |     #[foo]
    |       ^^^
 
-error: cannot find attribute macro `foo` in this scope
+error: cannot find attribute `foo` in this scope
   --> $DIR/custom_attribute.rs:7:7
    |
 LL |     #[foo]
diff --git a/src/test/ui/deprecation/deprecation-in-future.rs b/src/test/ui/deprecation/deprecation-in-future.rs
index c4f9fdc..464ddcc 100644
--- a/src/test/ui/deprecation/deprecation-in-future.rs
+++ b/src/test/ui/deprecation/deprecation-in-future.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![deny(deprecated_in_future)]
 
diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr
index b9e175e..038de80 100644
--- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr
+++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr
@@ -5,7 +5,7 @@
    | ------------------ method `clone` not found for this
 ...
 LL |     Bar::<NotClone> { x: 1 }.clone();
-   |                              ^^^^^
+   |                              ^^^^^ method not found in `Bar<NotClone>`
    |
    = note: the method `clone` exists but the following trait bounds were not satisfied:
            `Bar<NotClone> : std::clone::Clone`
diff --git a/src/test/ui/drop/dropck_legal_cycles.rs b/src/test/ui/drop/dropck_legal_cycles.rs
index a4f4c26..fb13fd7 100644
--- a/src/test/ui/drop/dropck_legal_cycles.rs
+++ b/src/test/ui/drop/dropck_legal_cycles.rs
@@ -143,7 +143,7 @@
     v[0].descend_into_self(&mut c);
     assert!(!c.saw_prev_marked); // <-- different from below, b/c acyclic above
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 1: { v[0] -> v[1], v[1] -> v[0] };
     // does not exercise `v` itself
@@ -158,7 +158,7 @@
     v[0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 2: { v[0] -> v, v[1] -> v }
     let v: V = Named::new("v");
@@ -171,7 +171,7 @@
     v.descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 3: { hk0 -> hv0, hv0 -> hk0, hk1 -> hv1, hv1 -> hk1 };
     // does not exercise `h` itself
@@ -193,7 +193,7 @@
         assert!(c.saw_prev_marked);
     }
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 4: { h -> (hmk0,hmv0,hmk1,hmv1), {hmk0,hmv0,hmk1,hmv1} -> h }
 
@@ -216,7 +216,7 @@
         // break;
     }
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 5: { vd[0] -> vd[1], vd[1] -> vd[0] };
     // does not exercise vd itself
@@ -232,7 +232,7 @@
     vd[0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 6: { vd -> (vd0, vd1), {vd0, vd1} -> vd }
     let mut vd: VecDeque<VD> = VecDeque::new();
@@ -247,7 +247,7 @@
     vd[0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 7: { vm -> (vm0, vm1), {vm0, vm1} -> vm }
     let mut vm: HashMap<usize, VM> = HashMap::new();
@@ -262,7 +262,7 @@
     vm[&0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 8: { ll -> (ll0, ll1), {ll0, ll1} -> ll }
     let mut ll: LinkedList<LL> = LinkedList::new();
@@ -282,7 +282,7 @@
         // break;
     }
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 9: { bh -> (bh0, bh1), {bh0, bh1} -> bh }
     let mut bh: BinaryHeap<BH> = BinaryHeap::new();
@@ -302,7 +302,7 @@
         // break;
     }
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 10: { btm -> (btk0, btv1), {bt0, bt1} -> btm }
     let mut btm: BTreeMap<BTM, BTM> = BTreeMap::new();
@@ -323,7 +323,7 @@
         // break;
     }
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 10: { bts -> (bts0, bts1), {bts0, bts1} -> btm }
     let mut bts: BTreeSet<BTS> = BTreeSet::new();
@@ -343,7 +343,7 @@
         // break;
     }
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 11: { rc0 -> (rc1, rc2), rc1 -> (), rc2 -> rc0 }
     let (rc0, rc1, rc2): (RCRC, RCRC, RCRC);
@@ -361,7 +361,7 @@
     rc0.descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // We want to take the previous Rc case and generalize it to Arc.
     //
@@ -395,7 +395,7 @@
     arc0.descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 13: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, rwlocks
     let (arc0, arc1, arc2): (ARCRW, ARCRW, ARCRW);
@@ -413,7 +413,7 @@
     arc0.descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
-    if PRINT { println!(""); }
+    if PRINT { println!(); }
 
     // Cycle 14: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, mutexs
     let (arc0, arc1, arc2): (ARCM, ARCM, ARCM);
diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs
index 79d09d1..91063ed 100644
--- a/src/test/ui/drop/dynamic-drop-async.rs
+++ b/src/test/ui/drop/dynamic-drop-async.rs
@@ -8,6 +8,7 @@
 // ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(slice_patterns)]
+#![allow(unused)]
 
 use std::{
     cell::{Cell, RefCell},
diff --git a/src/test/ui/elided-test.stderr b/src/test/ui/elided-test.stderr
index d22eee4..175bd03 100644
--- a/src/test/ui/elided-test.stderr
+++ b/src/test/ui/elided-test.stderr
@@ -1,6 +1,10 @@
 error[E0601]: `main` function not found in crate `elided_test`
+  --> $DIR/elided-test.rs:5:1
    |
-   = note: consider adding a `main` function to `$DIR/elided-test.rs`
+LL | / #[test]
+LL | | fn main() {
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/elided-test.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/empty/empty-macro-use.stderr b/src/test/ui/empty/empty-macro-use.stderr
index 1630041..8e3e068 100644
--- a/src/test/ui/empty/empty-macro-use.stderr
+++ b/src/test/ui/empty/empty-macro-use.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `macro_two!` in this scope
+error: cannot find macro `macro_two` in this scope
   --> $DIR/empty-macro-use.rs:7:5
    |
 LL |     macro_two!();
diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr
index a7f7cfa..7d59d55 100644
--- a/src/test/ui/empty/empty-never-array.stderr
+++ b/src/test/ui/empty/empty-never-array.stderr
@@ -3,6 +3,7 @@
    |
 LL | / enum Helper<T, U> {
 LL | |     T(T, [!; 0]),
+   | |     - not covered
 LL | |     #[allow(dead_code)]
 LL | |     U(U),
 LL | | }
diff --git a/src/test/ui/error-codes/E0008.rs b/src/test/ui/error-codes/E0008.rs
deleted file mode 100644
index c87ef4c..0000000
--- a/src/test/ui/error-codes/E0008.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    match Some("hi".to_string()) {
-        Some(s) if s.len() == 0 => {},
-        //~^ ERROR E0008
-        _ => {},
-    }
-}
diff --git a/src/test/ui/error-codes/E0008.stderr b/src/test/ui/error-codes/E0008.stderr
deleted file mode 100644
index 6b45439..0000000
--- a/src/test/ui/error-codes/E0008.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0008]: cannot bind by-move into a pattern guard
-  --> $DIR/E0008.rs:3:14
-   |
-LL |         Some(s) if s.len() == 0 => {},
-   |              ^ moves value into pattern guard
-   |
-   = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0008`.
diff --git a/src/test/ui/error-codes/E0044.rs b/src/test/ui/error-codes/E0044.rs
index a5265e7..9eee9c3 100644
--- a/src/test/ui/error-codes/E0044.rs
+++ b/src/test/ui/error-codes/E0044.rs
@@ -1,7 +1,7 @@
 extern {
     fn sqrt<T>(f: T) -> T;
     //~^ ERROR foreign items may not have type parameters [E0044]
-    //~| HELP use specialization instead of type parameters by replacing them with concrete types
+    //~| HELP replace the type parameters with concrete types
     //~| NOTE can't have type parameters
 }
 
diff --git a/src/test/ui/error-codes/E0044.stderr b/src/test/ui/error-codes/E0044.stderr
index 57c2111..e889c16 100644
--- a/src/test/ui/error-codes/E0044.stderr
+++ b/src/test/ui/error-codes/E0044.stderr
@@ -4,7 +4,7 @@
 LL |     fn sqrt<T>(f: T) -> T;
    |     ^^^^^^^^^^^^^^^^^^^^^^ can't have type parameters
    |
-   = help: use specialization instead of type parameters by replacing them with concrete types like `u32`
+   = help: replace the type parameters with concrete types like `u32`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0138.stderr b/src/test/ui/error-codes/E0138.stderr
index 745dccf..445053a 100644
--- a/src/test/ui/error-codes/E0138.stderr
+++ b/src/test/ui/error-codes/E0138.stderr
@@ -1,4 +1,4 @@
-error[E0138]: multiple 'start' functions
+error[E0138]: multiple `start` functions
   --> $DIR/E0138.rs:7:1
    |
 LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
diff --git a/src/test/ui/error-codes/E0301.rs b/src/test/ui/error-codes/E0301.rs
deleted file mode 100644
index 3b45180..0000000
--- a/src/test/ui/error-codes/E0301.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    match Some(()) {
-        None => { },
-        option if option.take().is_none() => {}, //~ ERROR E0301
-        Some(_) => { } //~^ ERROR E0596
-    }
-}
diff --git a/src/test/ui/error-codes/E0301.stderr b/src/test/ui/error-codes/E0301.stderr
deleted file mode 100644
index 4f12fd3..0000000
--- a/src/test/ui/error-codes/E0301.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0301]: cannot mutably borrow in a pattern guard
-  --> $DIR/E0301.rs:4:19
-   |
-LL |         option if option.take().is_none() => {},
-   |                   ^^^^^^ borrowed mutably in pattern guard
-   |
-   = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
-
-error[E0596]: cannot borrow `option` as mutable, as it is immutable for the pattern guard
-  --> $DIR/E0301.rs:4:19
-   |
-LL |         option if option.take().is_none() => {},
-   |                   ^^^^^^ cannot borrow as mutable
-   |
-   = note: variables bound in patterns are immutable until the end of the pattern guard
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0301, E0596.
-For more information about an error, try `rustc --explain E0301`.
diff --git a/src/test/ui/error-codes/E0302.rs b/src/test/ui/error-codes/E0302.rs
deleted file mode 100644
index 69f5953..0000000
--- a/src/test/ui/error-codes/E0302.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-fn main() {
-    match Some(()) {
-        None => { },
-        option if { option = None; false } => { }, //~ ERROR E0302
-        //~^ ERROR cannot assign to `option`, as it is immutable for the pattern guard
-        Some(_) => { }
-    }
-}
diff --git a/src/test/ui/error-codes/E0302.stderr b/src/test/ui/error-codes/E0302.stderr
deleted file mode 100644
index a077fca..0000000
--- a/src/test/ui/error-codes/E0302.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0302]: cannot assign in a pattern guard
-  --> $DIR/E0302.rs:4:21
-   |
-LL |         option if { option = None; false } => { },
-   |                     ^^^^^^^^^^^^^ assignment in pattern guard
-
-error[E0594]: cannot assign to `option`, as it is immutable for the pattern guard
-  --> $DIR/E0302.rs:4:21
-   |
-LL |         option if { option = None; false } => { },
-   |                     ^^^^^^^^^^^^^ cannot assign
-   |
-   = note: variables bound in patterns are immutable until the end of the pattern guard
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0302`.
diff --git a/src/test/ui/error-codes/E0601.rs b/src/test/ui/error-codes/E0601.rs
index 47feb7f..4380dde 100644
--- a/src/test/ui/error-codes/E0601.rs
+++ b/src/test/ui/error-codes/E0601.rs
@@ -1 +1 @@
-// Test for main function not found.
+//~ ERROR `main` function not found
diff --git a/src/test/ui/error-codes/E0601.stderr b/src/test/ui/error-codes/E0601.stderr
index cbc20db..a687f57 100644
--- a/src/test/ui/error-codes/E0601.stderr
+++ b/src/test/ui/error-codes/E0601.stderr
@@ -1,6 +1,8 @@
 error[E0601]: `main` function not found in crate `E0601`
+  --> $DIR/E0601.rs:1:37
    |
-   = note: consider adding a `main` function to `$DIR/E0601.rs`
+LL |
+   |                                     ^ consider adding a `main` function to `$DIR/E0601.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 8808e95..73571a3 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -24,7 +24,7 @@
   --> $DIR/error-festival.rs:16:7
    |
 LL |     x.z();
-   |       ^
+   |       ^ method not found in `&str`
 
 error[E0600]: cannot apply unary operator `!` to type `Question`
   --> $DIR/error-festival.rs:19:5
diff --git a/src/test/ui/ext-nonexistent.stderr b/src/test/ui/ext-nonexistent.stderr
index 3fbbb49..f3aa83f 100644
--- a/src/test/ui/ext-nonexistent.stderr
+++ b/src/test/ui/ext-nonexistent.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `iamnotanextensionthatexists!` in this scope
+error: cannot find macro `iamnotanextensionthatexists` in this scope
   --> $DIR/ext-nonexistent.rs:2:13
    |
 LL | fn main() { iamnotanextensionthatexists!(""); }
diff --git a/src/test/ui/extenv/issue-55897.rs b/src/test/ui/extenv/issue-55897.rs
index c3975f6..64c4107 100644
--- a/src/test/ui/extenv/issue-55897.rs
+++ b/src/test/ui/extenv/issue-55897.rs
@@ -1,7 +1,7 @@
 use prelude::*; //~ ERROR unresolved import `prelude`
 
 mod unresolved_env {
-    use env;
+    use env; //~ ERROR unresolved import `env`
 
     include!(concat!(env!("NON_EXISTENT"), "/data.rs"));
     //~^ ERROR cannot determine resolution for the macro `env`
diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr
index 9d68131..c57a467 100644
--- a/src/test/ui/extenv/issue-55897.stderr
+++ b/src/test/ui/extenv/issue-55897.stderr
@@ -19,6 +19,12 @@
    |     unresolved import
    |     help: a similar path exists: `std::prelude`
 
+error[E0432]: unresolved import `env`
+  --> $DIR/issue-55897.rs:4:9
+   |
+LL |     use env;
+   |         ^^^ no `env` in the root
+
 error: cannot determine resolution for the macro `env`
   --> $DIR/issue-55897.rs:6:22
    |
@@ -27,6 +33,6 @@
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0432`.
diff --git a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs
index 92844f9..b6c8648 100644
--- a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs
+++ b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.rs
@@ -1,4 +1,4 @@
-//~ ERROR kind="static-nobundle" is feature gated
+//~ ERROR kind="static-nobundle" is unstable
 // Test the behavior of rustc when non-existent library is statically linked
 
 // compile-flags: -l static-nobundle=nonexistent
diff --git a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr
index 059559d..cfff4c3 100644
--- a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr
+++ b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr
@@ -1,4 +1,4 @@
-error[E0658]: kind="static-nobundle" is feature gated
+error[E0658]: kind="static-nobundle" is unstable
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/37403
    = help: add `#![feature(static_nobundle)]` to the crate attributes to enable
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
index 6d51bb3..68ff95e 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
@@ -84,12 +84,12 @@
 #![crate_name = "0900"]
 #![crate_type = "bin"] // cannot pass "0800" here
 
-// For #![crate_id], see issue #43142. (I cannot bear to enshrine current behavior in a test)
+#![crate_id = "10"] //~ WARN use of deprecated attribute
 
 // FIXME(#44232) we should warn that this isn't used.
 #![feature(rust1)]
 
-// For #![no_start], see issue #43144. (I cannot bear to enshrine current behavior in a test)
+#![no_start] //~ WARN use of deprecated attribute
 
 // (cannot easily gating state of crate-level #[no_main]; but non crate-level is below at "0400")
 #![no_builtins]
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
index 864df35..b2a6018 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
@@ -186,6 +186,20 @@
    |
    = help: consider an outer attribute, `#[macro_use]` mod ...
 
+warning: use of deprecated attribute `crate_id`: no longer used.
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:87:1
+   |
+LL | #![crate_id = "10"]
+   | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+warning: use of deprecated attribute `no_start`: no longer used.
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:92:1
+   |
+LL | #![no_start]
+   | ^^^^^^^^^^^^ help: remove this attribute
+
 warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:12
    |
diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs
index 41c9f79..61da38e 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.rs
+++ b/src/test/ui/feature-gates/feature-gate-abi.rs
@@ -10,7 +10,9 @@
 
 // Functions
 extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
+//~^ ERROR intrinsic must be in
 extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
+//~^ ERROR intrinsic must be in
 extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
 extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change
 extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -22,7 +24,9 @@
 // Methods in trait definition
 trait Tr {
     extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change
+    //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
+    //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental
@@ -31,8 +35,6 @@
     extern "thiscall" fn m8(); //~ ERROR thiscall is experimental and subject to change
     extern "amdgpu-kernel" fn m9(); //~ ERROR amdgpu-kernel ABI is experimental and subject to change
 
-    extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change
-    extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental
     extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -47,7 +49,9 @@
 // Methods in trait impl
 impl Tr for S {
     extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change
+    //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
+    //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -60,7 +64,9 @@
 // Methods in inherent impl
 impl S {
     extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change
+    //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
+    //~^ ERROR intrinsic must be in
     extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental
diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr
index 88e0b86..afda76d 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi.stderr
@@ -7,7 +7,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:13:1
+  --> $DIR/feature-gate-abi.rs:14:1
    |
 LL | extern "platform-intrinsic" fn f2() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@
    = 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:14:1
+  --> $DIR/feature-gate-abi.rs:16:1
    |
 LL | extern "vectorcall" fn f3() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@
    = 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:15:1
+  --> $DIR/feature-gate-abi.rs:17:1
    |
 LL | extern "rust-call" fn f4() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@
    = 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:16:1
+  --> $DIR/feature-gate-abi.rs:18:1
    |
 LL | extern "msp430-interrupt" fn f5() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@
    = 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:17:1
+  --> $DIR/feature-gate-abi.rs:19:1
    |
 LL | extern "ptx-kernel" fn f6() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@
    = 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:18:1
+  --> $DIR/feature-gate-abi.rs:20:1
    |
 LL | extern "x86-interrupt" fn f7() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@
    = 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:19:1
+  --> $DIR/feature-gate-abi.rs:21:1
    |
 LL | extern "thiscall" fn f8() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@
    = 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:20:1
+  --> $DIR/feature-gate-abi.rs:22:1
    |
 LL | extern "amdgpu-kernel" fn f9() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:24:5
+  --> $DIR/feature-gate-abi.rs:26:5
    |
 LL |     extern "rust-intrinsic" fn m1();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:25:5
+  --> $DIR/feature-gate-abi.rs:28:5
    |
 LL |     extern "platform-intrinsic" fn m2();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +94,7 @@
    = 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:26:5
+  --> $DIR/feature-gate-abi.rs:30:5
    |
 LL |     extern "vectorcall" fn m3();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -102,7 +102,7 @@
    = 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:27:5
+  --> $DIR/feature-gate-abi.rs:31:5
    |
 LL |     extern "rust-call" fn m4();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,7 +111,7 @@
    = 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:28:5
+  --> $DIR/feature-gate-abi.rs:32:5
    |
 LL |     extern "msp430-interrupt" fn m5();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@
    = 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:29:5
+  --> $DIR/feature-gate-abi.rs:33:5
    |
 LL |     extern "ptx-kernel" fn m6();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -129,7 +129,7 @@
    = 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:30:5
+  --> $DIR/feature-gate-abi.rs:34:5
    |
 LL |     extern "x86-interrupt" fn m7();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -138,7 +138,7 @@
    = 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:31:5
+  --> $DIR/feature-gate-abi.rs:35:5
    |
 LL |     extern "thiscall" fn m8();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -146,7 +146,7 @@
    = 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:32:5
+  --> $DIR/feature-gate-abi.rs:36:5
    |
 LL |     extern "amdgpu-kernel" fn m9();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,25 +154,8 @@
    = 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]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:34:5
-   |
-LL |     extern "rust-intrinsic" fn dm1() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-
-error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:35:5
-   |
-LL |     extern "platform-intrinsic" fn dm2() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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:36:5
+  --> $DIR/feature-gate-abi.rs:38:5
    |
 LL |     extern "vectorcall" fn dm3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -180,7 +163,7 @@
    = 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:37:5
+  --> $DIR/feature-gate-abi.rs:39:5
    |
 LL |     extern "rust-call" fn dm4() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -189,7 +172,7 @@
    = 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:38:5
+  --> $DIR/feature-gate-abi.rs:40:5
    |
 LL |     extern "msp430-interrupt" fn dm5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +181,7 @@
    = 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:39:5
+  --> $DIR/feature-gate-abi.rs:41:5
    |
 LL |     extern "ptx-kernel" fn dm6() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -207,7 +190,7 @@
    = 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:40:5
+  --> $DIR/feature-gate-abi.rs:42:5
    |
 LL |     extern "x86-interrupt" fn dm7() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -216,7 +199,7 @@
    = 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:41:5
+  --> $DIR/feature-gate-abi.rs:43:5
    |
 LL |     extern "thiscall" fn dm8() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -224,7 +207,7 @@
    = 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:42:5
+  --> $DIR/feature-gate-abi.rs:44:5
    |
 LL |     extern "amdgpu-kernel" fn dm9() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -233,7 +216,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:49:5
+  --> $DIR/feature-gate-abi.rs:51:5
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +224,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:50:5
+  --> $DIR/feature-gate-abi.rs:53:5
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +233,7 @@
    = 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:51:5
+  --> $DIR/feature-gate-abi.rs:55:5
    |
 LL |     extern "vectorcall" fn m3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -258,7 +241,7 @@
    = 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:52:5
+  --> $DIR/feature-gate-abi.rs:56:5
    |
 LL |     extern "rust-call" fn m4() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -267,7 +250,7 @@
    = 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:53:5
+  --> $DIR/feature-gate-abi.rs:57:5
    |
 LL |     extern "msp430-interrupt" fn m5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -276,7 +259,7 @@
    = 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:54:5
+  --> $DIR/feature-gate-abi.rs:58:5
    |
 LL |     extern "ptx-kernel" fn m6() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -285,7 +268,7 @@
    = 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:55:5
+  --> $DIR/feature-gate-abi.rs:59:5
    |
 LL |     extern "x86-interrupt" fn m7() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -294,7 +277,7 @@
    = 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:56:5
+  --> $DIR/feature-gate-abi.rs:60:5
    |
 LL |     extern "thiscall" fn m8() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -302,7 +285,7 @@
    = 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:57:5
+  --> $DIR/feature-gate-abi.rs:61:5
    |
 LL |     extern "amdgpu-kernel" fn m9() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -311,7 +294,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:62:5
+  --> $DIR/feature-gate-abi.rs:66:5
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -319,7 +302,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:63:5
+  --> $DIR/feature-gate-abi.rs:68:5
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -328,7 +311,7 @@
    = 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:64:5
+  --> $DIR/feature-gate-abi.rs:70:5
    |
 LL |     extern "vectorcall" fn im3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -336,7 +319,7 @@
    = 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:65:5
+  --> $DIR/feature-gate-abi.rs:71:5
    |
 LL |     extern "rust-call" fn im4() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -345,7 +328,7 @@
    = 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:66:5
+  --> $DIR/feature-gate-abi.rs:72:5
    |
 LL |     extern "msp430-interrupt" fn im5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -354,7 +337,7 @@
    = 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:67:5
+  --> $DIR/feature-gate-abi.rs:73:5
    |
 LL |     extern "ptx-kernel" fn im6() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -363,7 +346,7 @@
    = 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:68:5
+  --> $DIR/feature-gate-abi.rs:74:5
    |
 LL |     extern "x86-interrupt" fn im7() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -372,7 +355,7 @@
    = 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:69:5
+  --> $DIR/feature-gate-abi.rs:75:5
    |
 LL |     extern "thiscall" fn im8() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -380,7 +363,7 @@
    = 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:70:5
+  --> $DIR/feature-gate-abi.rs:76:5
    |
 LL |     extern "amdgpu-kernel" fn im9() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -389,7 +372,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:74:11
+  --> $DIR/feature-gate-abi.rs:80:11
    |
 LL | type A1 = extern "rust-intrinsic" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -397,7 +380,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:75:11
+  --> $DIR/feature-gate-abi.rs:81:11
    |
 LL | type A2 = extern "platform-intrinsic" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -406,7 +389,7 @@
    = 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:76:11
+  --> $DIR/feature-gate-abi.rs:82:11
    |
 LL | type A3 = extern "vectorcall" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -414,7 +397,7 @@
    = 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:77:11
+  --> $DIR/feature-gate-abi.rs:83:11
    |
 LL | type A4 = extern "rust-call" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -423,7 +406,7 @@
    = 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:78:11
+  --> $DIR/feature-gate-abi.rs:84:11
    |
 LL | type A5 = extern "msp430-interrupt" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -432,7 +415,7 @@
    = 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:79:11
+  --> $DIR/feature-gate-abi.rs:85:11
    |
 LL | type A6 = extern "ptx-kernel" fn ();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -441,7 +424,7 @@
    = 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:80:11
+  --> $DIR/feature-gate-abi.rs:86:11
    |
 LL | type A7 = extern "x86-interrupt" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -450,7 +433,7 @@
    = 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:81:11
+  --> $DIR/feature-gate-abi.rs:87:11
    |
 LL | type A8 = extern "thiscall" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^
@@ -458,7 +441,7 @@
    = 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:82:11
+  --> $DIR/feature-gate-abi.rs:88:11
    |
 LL | type A9 = extern "amdgpu-kernel" fn();
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -467,7 +450,7 @@
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:85:1
+  --> $DIR/feature-gate-abi.rs:91:1
    |
 LL | extern "rust-intrinsic" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -475,7 +458,7 @@
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:86:1
+  --> $DIR/feature-gate-abi.rs:92:1
    |
 LL | extern "platform-intrinsic" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -484,7 +467,7 @@
    = 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:87:1
+  --> $DIR/feature-gate-abi.rs:93:1
    |
 LL | extern "vectorcall" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -492,7 +475,7 @@
    = 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:88:1
+  --> $DIR/feature-gate-abi.rs:94:1
    |
 LL | extern "rust-call" {}
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -501,7 +484,7 @@
    = 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:89:1
+  --> $DIR/feature-gate-abi.rs:95:1
    |
 LL | extern "msp430-interrupt" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -510,7 +493,7 @@
    = 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:90:1
+  --> $DIR/feature-gate-abi.rs:96:1
    |
 LL | extern "ptx-kernel" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -519,7 +502,7 @@
    = 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:91:1
+  --> $DIR/feature-gate-abi.rs:97:1
    |
 LL | extern "x86-interrupt" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -528,7 +511,7 @@
    = 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:92:1
+  --> $DIR/feature-gate-abi.rs:98:1
    |
 LL | extern "thiscall" {}
    | ^^^^^^^^^^^^^^^^^^^^
@@ -536,7 +519,7 @@
    = 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:93:1
+  --> $DIR/feature-gate-abi.rs:99:1
    |
 LL | extern "amdgpu-kernel" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -544,6 +527,54 @@
    = 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: aborting due to 63 previous errors
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:26:32
+   |
+LL |     extern "rust-intrinsic" fn m1();
+   |                                ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:28:36
+   |
+LL |     extern "platform-intrinsic" fn m2();
+   |                                    ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:12:33
+   |
+LL | extern "rust-intrinsic" fn f1() {}
+   |                                 ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:14:37
+   |
+LL | extern "platform-intrinsic" fn f2() {}
+   |                                     ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:51:37
+   |
+LL |     extern "rust-intrinsic" fn m1() {}
+   |                                     ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:53:41
+   |
+LL |     extern "platform-intrinsic" fn m2() {}
+   |                                         ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:66:38
+   |
+LL |     extern "rust-intrinsic" fn im1() {}
+   |                                      ^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-abi.rs:68:42
+   |
+LL |     extern "platform-intrinsic" fn im2() {}
+   |                                          ^^
+
+error: aborting due to 69 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
index d34936b..936cab2 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
@@ -1,18 +1,18 @@
 // Check that literals in attributes parse just fine.
 
-#[fake_attr] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(100)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(1, 2, 3)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr("hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(name = "hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR cannot find attribute macro `fake_attr` in th
-#[fake_attr(key = "hello", val = 10)] //~ ERROR cannot find attribute macro `fake_attr` in this scop
-#[fake_attr(key("hello"), val(10))] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(enabled = true, disabled = false)] //~ ERROR cannot find attribute macro `fake_attr` in
-#[fake_attr(true)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(pi = 3.14159)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_attr(b"hi")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
-#[fake_doc(r"doc")] //~ ERROR cannot find attribute macro `fake_doc` in this scope
+#[fake_attr] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(100)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(1, 2, 3)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr("hello")] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(name = "hello")] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR cannot find attribute `fake_attr` in th
+#[fake_attr(key = "hello", val = 10)] //~ ERROR cannot find attribute `fake_attr` in this scop
+#[fake_attr(key("hello"), val(10))] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(enabled = true, disabled = false)] //~ ERROR cannot find attribute `fake_attr` in
+#[fake_attr(true)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(pi = 3.14159)] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_attr(b"hi")] //~ ERROR cannot find attribute `fake_attr` in this scope
+#[fake_doc(r"doc")] //~ ERROR cannot find attribute `fake_doc` in this scope
 struct Q {}
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
index efdc2d1..b7c45ec 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
@@ -1,76 +1,76 @@
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:3:3
    |
 LL | #[fake_attr]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:4:3
    |
 LL | #[fake_attr(100)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:5:3
    |
 LL | #[fake_attr(1, 2, 3)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:6:3
    |
 LL | #[fake_attr("hello")]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:7:3
    |
 LL | #[fake_attr(name = "hello")]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:8:3
    |
 LL | #[fake_attr(1, "hi", key = 12, true, false)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:9:3
    |
 LL | #[fake_attr(key = "hello", val = 10)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:10:3
    |
 LL | #[fake_attr(key("hello"), val(10))]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:11:3
    |
 LL | #[fake_attr(enabled = true, disabled = false)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:12:3
    |
 LL | #[fake_attr(true)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:13:3
    |
 LL | #[fake_attr(pi = 3.14159)]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_attr` in this scope
+error: cannot find attribute `fake_attr` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:14:3
    |
 LL | #[fake_attr(b"hi")]
    |   ^^^^^^^^^
 
-error: cannot find attribute macro `fake_doc` in this scope
+error: cannot find attribute `fake_doc` in this scope
   --> $DIR/feature-gate-custom_attribute.rs:15:3
    |
 LL | #[fake_doc(r"doc")]
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs b/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs
index 8fe11cb..e4c8014 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.rs
@@ -4,54 +4,54 @@
 // gate-test-custom_attribute
 
 struct StLt<#[lt_struct] 'a>(&'a u32);
-//~^ ERROR the attribute `lt_struct` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `lt_struct` in this scope
 struct StTy<#[ty_struct] I>(I);
-//~^ ERROR the attribute `ty_struct` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `ty_struct` in this scope
 
 enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
-//~^ ERROR the attribute `lt_enum` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `lt_enum` in this scope
 enum EnTy<#[ty_enum] J> { A(J), B }
-//~^ ERROR the attribute `ty_enum` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `ty_enum` in this scope
 
 trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
-//~^ ERROR the attribute `lt_trait` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `lt_trait` in this scope
 trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
-//~^ ERROR the attribute `ty_trait` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `ty_trait` in this scope
 
 type TyLt<#[lt_type] 'd> = &'d u32;
-//~^ ERROR the attribute `lt_type` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `lt_type` in this scope
 type TyTy<#[ty_type] L> = (L, );
-//~^ ERROR the attribute `ty_type` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `ty_type` in this scope
 
 impl<#[lt_inherent] 'e> StLt<'e> { }
-//~^ ERROR the attribute `lt_inherent` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `lt_inherent` in this scope
 impl<#[ty_inherent] M> StTy<M> { }
-//~^ ERROR the attribute `ty_inherent` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `ty_inherent` in this scope
 
 impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
-    //~^ ERROR the attribute `lt_impl_for` is currently unknown to the compiler
+    //~^ ERROR cannot find attribute `lt_impl_for` in this scope
     fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
 }
 impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
-    //~^ ERROR the attribute `ty_impl_for` is currently unknown to the compiler
+    //~^ ERROR cannot find attribute `ty_impl_for` in this scope
     fn foo(&self, _: N) { }
 }
 
 fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
-//~^ ERROR the attribute `lt_fn` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `lt_fn` in this scope
 fn f_ty<#[ty_fn] O>(_: O) { }
-//~^ ERROR the attribute `ty_fn` is currently unknown to the compiler
+//~^ ERROR cannot find attribute `ty_fn` in this scope
 
 impl<I> StTy<I> {
     fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
-    //~^ ERROR the attribute `lt_meth` is currently unknown to the compiler
+    //~^ ERROR cannot find attribute `lt_meth` in this scope
     fn m_ty<#[ty_meth] P>(_: P) { }
-    //~^ ERROR the attribute `ty_meth` is currently unknown to the compiler
+    //~^ ERROR cannot find attribute `ty_meth` in this scope
 }
 
 fn hof_lt<Q>(_: Q)
     where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
-    //~^ ERROR the attribute `lt_hof` is currently unknown to the compiler
+    //~^ ERROR cannot find attribute `lt_hof` in this scope
 {
 }
 
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr
index 15e0c41..bc89cad 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr
@@ -1,156 +1,104 @@
-error[E0658]: the attribute `lt_struct` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:6:13
-   |
-LL | struct StLt<#[lt_struct] 'a>(&'a u32);
-   |             ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_struct` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:8:13
-   |
-LL | struct StTy<#[ty_struct] I>(I);
-   |             ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_enum` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:11:11
-   |
-LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
-   |           ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_enum` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:13:11
-   |
-LL | enum EnTy<#[ty_enum] J> { A(J), B }
-   |           ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_trait` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:16:12
-   |
-LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
-   |            ^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_trait` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:18:12
-   |
-LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
-   |            ^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_type` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:21:11
-   |
-LL | type TyLt<#[lt_type] 'd> = &'d u32;
-   |           ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_type` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:23:11
-   |
-LL | type TyTy<#[ty_type] L> = (L, );
-   |           ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_inherent` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:26:6
-   |
-LL | impl<#[lt_inherent] 'e> StLt<'e> { }
-   |      ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_inherent` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:28:6
-   |
-LL | impl<#[ty_inherent] M> StTy<M> { }
-   |      ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_impl_for` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:31:6
-   |
-LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
-   |      ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_impl_for` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:35:6
-   |
-LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
-   |      ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_fn` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:40:9
-   |
-LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
-   |         ^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_fn` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:42:9
-   |
-LL | fn f_ty<#[ty_fn] O>(_: O) { }
-   |         ^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_meth` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:46:13
-   |
-LL |     fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
-   |             ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `ty_meth` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:48:13
-   |
-LL |     fn m_ty<#[ty_meth] P>(_: P) { }
-   |             ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `lt_hof` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute2.rs:53:19
+error: cannot find attribute `lt_hof` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:53:21
    |
 LL |     where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
-   |                   ^^^^^^^^^
+   |                     ^^^^^^
+
+error: cannot find attribute `ty_meth` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:48:15
    |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
+LL |     fn m_ty<#[ty_meth] P>(_: P) { }
+   |               ^^^^^^^
+
+error: cannot find attribute `lt_meth` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:46:15
+   |
+LL |     fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+   |               ^^^^^^^
+
+error: cannot find attribute `ty_fn` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:42:11
+   |
+LL | fn f_ty<#[ty_fn] O>(_: O) { }
+   |           ^^^^^
+
+error: cannot find attribute `lt_fn` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:40:11
+   |
+LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+   |           ^^^^^
+
+error: cannot find attribute `ty_impl_for` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:35:8
+   |
+LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
+   |        ^^^^^^^^^^^
+
+error: cannot find attribute `lt_impl_for` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:31:8
+   |
+LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+   |        ^^^^^^^^^^^
+
+error: cannot find attribute `ty_inherent` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:28:8
+   |
+LL | impl<#[ty_inherent] M> StTy<M> { }
+   |        ^^^^^^^^^^^
+
+error: cannot find attribute `lt_inherent` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:26:8
+   |
+LL | impl<#[lt_inherent] 'e> StLt<'e> { }
+   |        ^^^^^^^^^^^
+
+error: cannot find attribute `ty_type` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:23:13
+   |
+LL | type TyTy<#[ty_type] L> = (L, );
+   |             ^^^^^^^
+
+error: cannot find attribute `lt_type` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:21:13
+   |
+LL | type TyLt<#[lt_type] 'd> = &'d u32;
+   |             ^^^^^^^
+
+error: cannot find attribute `ty_trait` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:18:14
+   |
+LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
+   |              ^^^^^^^^
+
+error: cannot find attribute `lt_trait` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:16:14
+   |
+LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+   |              ^^^^^^^^
+
+error: cannot find attribute `ty_enum` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:13:13
+   |
+LL | enum EnTy<#[ty_enum] J> { A(J), B }
+   |             ^^^^^^^
+
+error: cannot find attribute `lt_enum` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:11:13
+   |
+LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
+   |             ^^^^^^^
+
+error: cannot find attribute `ty_struct` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:8:15
+   |
+LL | struct StTy<#[ty_struct] I>(I);
+   |               ^^^^^^^^^
+
+error: cannot find attribute `lt_struct` in this scope
+  --> $DIR/feature-gate-custom_attribute2.rs:6:15
+   |
+LL | struct StLt<#[lt_struct] 'a>(&'a u32);
+   |               ^^^^^^^^^
 
 error: aborting due to 17 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.rs b/src/test/ui/feature-gates/feature-gate-doc_alias.rs
index adb6fc2..c957221 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_alias.rs
+++ b/src/test/ui/feature-gates/feature-gate-doc_alias.rs
@@ -1,4 +1,4 @@
-#[doc(alias = "foo")] //~ ERROR: `#[doc(alias = "...")]` is experimental
+#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental
 pub struct Foo;
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr
index dddaa45..540b1f5 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr
+++ b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(alias = "...")]` is experimental
+error[E0658]: `#[doc(alias)]` is experimental
   --> $DIR/feature-gate-doc_alias.rs:1:1
    |
 LL | #[doc(alias = "foo")]
diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs b/src/test/ui/feature-gates/feature-gate-doc_cfg.rs
index bb3846e..b12b8a1 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs
+++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.rs
@@ -1,2 +1,2 @@
-#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg(...))]` is experimental
+#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg)]` is experimental
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr
index 7b0a231..eaa908d 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr
+++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(cfg(...))]` is experimental
+error[E0658]: `#[doc(cfg)]` is experimental
   --> $DIR/feature-gate-doc_cfg.rs:1:1
    |
 LL | #[doc(cfg(unix))]
diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs b/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
index 6cdcfa6..4bb9a40 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
+++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
@@ -1,4 +1,4 @@
-#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword = "...")]` is experimental
+#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword)]` is experimental
 /// wonderful
 mod foo{}
 
diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
index abde0be..15a41d9 100644
--- a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
+++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(keyword = "...")]` is experimental
+error[E0658]: `#[doc(keyword)]` is experimental
   --> $DIR/feature-gate-doc_keyword.rs:1:1
    |
 LL | #[doc(keyword = "match")]
diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.rs b/src/test/ui/feature-gates/feature-gate-external_doc.rs
index dec3fa1..9d68d3e 100644
--- a/src/test/ui/feature-gates/feature-gate-external_doc.rs
+++ b/src/test/ui/feature-gates/feature-gate-external_doc.rs
@@ -1,2 +1,2 @@
-#[doc(include="asdf.md")] //~ ERROR: `#[doc(include = "...")]` is experimental
+#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.stderr b/src/test/ui/feature-gates/feature-gate-external_doc.stderr
index a5a8743..683c0ad 100644
--- a/src/test/ui/feature-gates/feature-gate-external_doc.stderr
+++ b/src/test/ui/feature-gates/feature-gate-external_doc.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `#[doc(include = "...")]` is experimental
+error[E0658]: `#[doc(include)]` is experimental
   --> $DIR/feature-gate-external_doc.rs:1:1
    |
 LL | #[doc(include="asdf.md")]
diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.rs b/src/test/ui/feature-gates/feature-gate-intrinsics.rs
index d1da943..e0dc3cc 100644
--- a/src/test/ui/feature-gates/feature-gate-intrinsics.rs
+++ b/src/test/ui/feature-gates/feature-gate-intrinsics.rs
@@ -3,5 +3,6 @@
 }
 
 extern "rust-intrinsic" fn baz() {} //~ ERROR intrinsics are subject to change
+//~^ ERROR intrinsic must be in
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
index 09843f0..101a10e 100644
--- a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
+++ b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr
@@ -22,7 +22,13 @@
 LL |     fn bar();
    |     ^^^^^^^^^ unrecognized intrinsic
 
-error: aborting due to 3 previous errors
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/feature-gate-intrinsics.rs:5:34
+   |
+LL | extern "rust-intrinsic" fn baz() {}
+   |                                  ^^
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0093, E0658.
 For more information about an error, try `rustc --explain E0093`.
diff --git a/src/test/ui/feature-gates/feature-gate-is_sorted.rs b/src/test/ui/feature-gates/feature-gate-is_sorted.rs
index 078ecc5..359ed83 100644
--- a/src/test/ui/feature-gates/feature-gate-is_sorted.rs
+++ b/src/test/ui/feature-gates/feature-gate-is_sorted.rs
@@ -1,11 +1,11 @@
 fn main() {
-    // Assert `Iterator` methods are feature gated
+    // Assert `Iterator` methods are unstable
     assert!([1, 2, 2, 9].iter().is_sorted());
     //~^ ERROR: use of unstable library feature 'is_sorted': new API
     assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
     //~^ ERROR: use of unstable library feature 'is_sorted': new API
 
-    // Assert `[T]` methods are feature gated
+    // Assert `[T]` methods are unstable
     assert!([1, 2, 2, 9].is_sorted());
     //~^ ERROR: use of unstable library feature 'is_sorted': new API
     assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
diff --git a/src/test/ui/feature-gates/feature-gate-link_cfg.rs b/src/test/ui/feature-gates/feature-gate-link_cfg.rs
index 1905346..27ec2e9 100644
--- a/src/test/ui/feature-gates/feature-gate-link_cfg.rs
+++ b/src/test/ui/feature-gates/feature-gate-link_cfg.rs
@@ -1,5 +1,5 @@
 #[link(name = "foo", cfg(foo))]
-//~^ ERROR: is feature gated
+//~^ ERROR: is unstable
 extern {}
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr
index 58aa4ed..f6c5061 100644
--- a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr
+++ b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr
@@ -1,4 +1,4 @@
-error[E0658]: is feature gated
+error[E0658]: is unstable
   --> $DIR/feature-gate-link_cfg.rs:1:1
    |
 LL | #[link(name = "foo", cfg(foo))]
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
index 4044fd2..c985298 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
@@ -19,5 +19,5 @@
 //~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests
 #[rustc_unknown]
 //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
-//~| ERROR cannot find attribute macro `rustc_unknown` in this scope
+//~| ERROR cannot find attribute `rustc_unknown` in this scope
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
index c106302..d6fdab2 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
@@ -37,7 +37,7 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error: cannot find attribute macro `rustc_unknown` in this scope
+error: cannot find attribute `rustc_unknown` in this scope
   --> $DIR/feature-gate-rustc-attrs.rs:20:3
    |
 LL | #[rustc_unknown]
diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs
index 1ce6c54..644b1f9 100644
--- a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs
+++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs
@@ -1,5 +1,5 @@
 #[link(name="foo", kind="static-nobundle")]
-//~^ ERROR: kind="static-nobundle" is feature gated
+//~^ ERROR: kind="static-nobundle" is unstable
 extern {}
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
index f2e29cf..cc0d426 100644
--- a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
+++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
@@ -1,4 +1,4 @@
-error[E0658]: kind="static-nobundle" is feature gated
+error[E0658]: kind="static-nobundle" is unstable
   --> $DIR/feature-gate-static-nobundle.rs:1:1
    |
 LL | #[link(name="foo", kind="static-nobundle")]
diff --git a/src/test/ui/feature-gates/feature-gate-type_ascription.rs b/src/test/ui/feature-gates/feature-gate-type_ascription.rs
index e42e340..7a59715 100644
--- a/src/test/ui/feature-gates/feature-gate-type_ascription.rs
+++ b/src/test/ui/feature-gates/feature-gate-type_ascription.rs
@@ -1,4 +1,4 @@
-// Type ascription is feature gated
+// Type ascription is unstable
 
 fn main() {
     let a = 10: u8; //~ ERROR type ascription is experimental
diff --git a/src/test/ui/for/for-c-in-str.rs b/src/test/ui/for/for-c-in-str.rs
index 43b1a04..0fbc796 100644
--- a/src/test/ui/for/for-c-in-str.rs
+++ b/src/test/ui/for/for-c-in-str.rs
@@ -6,6 +6,6 @@
     //~| NOTE `&str` is not an iterator
     //~| HELP the trait `std::iter::Iterator` is not implemented for `&str`
     //~| NOTE required by `std::iter::IntoIterator::into_iter`
-        println!("");
+        println!();
     }
 }
diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr
index 0d77fd4..14aea2d 100644
--- a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr
+++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in `for` loop binding: `&std::i32::MIN..=0i32` not covered
+error[E0005]: refutable pattern in `for` loop binding: `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered
   --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9
    |
 LL |     for &1 in [1].iter() {}
-   |         ^^ pattern `&std::i32::MIN..=0i32` not covered
+   |         ^^ patterns `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr
index 92f92e2..dab4d34 100644
--- a/src/test/ui/generator/auto-trait-regions.stderr
+++ b/src/test/ui/generator/auto-trait-regions.stderr
@@ -1,20 +1,26 @@
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:30:5
    |
+LL | auto trait Foo {}
+   | ----------------- trait `Foo` defined here
+...
 LL |     assert_foo(gen);
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`
-   = note: but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
+   = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
 
 error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:48:5
    |
+LL | auto trait Foo {}
+   | ----------------- trait `Foo` defined here
+...
 LL |     assert_foo(gen);
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`
-   = note: but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
+   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generic/generic-extern.stderr b/src/test/ui/generic/generic-extern.stderr
index e7625ab..c90215b 100644
--- a/src/test/ui/generic/generic-extern.stderr
+++ b/src/test/ui/generic/generic-extern.stderr
@@ -4,7 +4,7 @@
 LL |     fn foo<T>();
    |     ^^^^^^^^^^^^ can't have type parameters
    |
-   = help: use specialization instead of type parameters by replacing them with concrete types like `u32`
+   = help: replace the type parameters with concrete types like `u32`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/due-to-where-clause.rs b/src/test/ui/hrtb/due-to-where-clause.rs
new file mode 100644
index 0000000..04e2ddd
--- /dev/null
+++ b/src/test/ui/hrtb/due-to-where-clause.rs
@@ -0,0 +1,16 @@
+// ignore-compare-mode-nll
+// ^ This code works in nll mode.
+
+fn main() {
+    test::<FooS>(&mut 42); //~ ERROR implementation of `Foo` is not general enough
+}
+
+trait Foo<'a> {}
+
+struct FooS<'a> {
+    data: &'a mut u32,
+}
+
+impl<'a, 'b: 'a> Foo<'b> for FooS<'a> {}
+
+fn test<'a, F>(data: &'a mut u32) where F: for<'b> Foo<'b> {}
diff --git a/src/test/ui/hrtb/due-to-where-clause.stderr b/src/test/ui/hrtb/due-to-where-clause.stderr
new file mode 100644
index 0000000..e698584
--- /dev/null
+++ b/src/test/ui/hrtb/due-to-where-clause.stderr
@@ -0,0 +1,17 @@
+error: implementation of `Foo` is not general enough
+  --> $DIR/due-to-where-clause.rs:5:5
+   |
+LL |     test::<FooS>(&mut 42);
+   |     ^^^^^^^^^^^^ doesn't satisfy where-clause
+...
+LL | trait Foo<'a> {}
+   | ---------------- trait `Foo` defined here
+...
+LL | fn test<'a, F>(data: &'a mut u32) where F: for<'b> Foo<'b> {}
+   | ------------------------------------------------------------- due to a where-clause on `test`...
+   |
+   = note: ...`FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`...
+   = note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
index 77a5491..003f326 100644
--- a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
+++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr
@@ -1,11 +1,14 @@
 error: implementation of `Deserialize` is not general enough
   --> $DIR/hrtb-cache-issue-54302.rs:19:5
    |
+LL | trait Deserialize<'de> {}
+   | ------------------------- trait `Deserialize` defined here
+...
 LL |     assert_deserialize_owned::<&'static str>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
    |
-   = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`
-   = note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
+   = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`...
+   = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr
index e7deca7..c0e3fd3 100644
--- a/src/test/ui/hrtb/issue-30786.migrate.stderr
+++ b/src/test/ui/hrtb/issue-30786.migrate.stderr
@@ -1,11 +1,17 @@
 error: implementation of `Stream` is not general enough
   --> $DIR/issue-30786.rs:108:22
    |
-LL |     let map = source.map(|x: &_| x);
-   |                      ^^^
+LL | / pub trait Stream {
+LL | |     type Item;
+LL | |     fn next(self) -> Option<Self::Item>;
+LL | | }
+   | |_- trait `Stream` defined here
+...
+LL |       let map = source.map(|x: &_| x);
+   |                        ^^^ implementation of `Stream` is not general enough
    |
-   = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`
-   = note: but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
+   = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`...
+   = note: ...but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr
index 8614d86..1cfd93e 100644
--- a/src/test/ui/hrtb/issue-30786.nll.stderr
+++ b/src/test/ui/hrtb/issue-30786.nll.stderr
@@ -1,11 +1,11 @@
 error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:112:18
+  --> $DIR/issue-30786.rs:113:18
    |
 LL |     let filter = map.filter(|x: &_| true);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:17
+  --> $DIR/issue-30786.rs:115:17
    |
 LL |     let count = filter.count(); // Assert that we still have a valid stream.
    |                 ^^^^^^^^^^^^^^
diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs
index b9920a1..c42297c 100644
--- a/src/test/ui/hrtb/issue-30786.rs
+++ b/src/test/ui/hrtb/issue-30786.rs
@@ -16,7 +16,7 @@
 
 //[nll]compile-flags: -Z borrowck=mir
 
-pub trait Stream {
+pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here
     type Item;
     fn next(self) -> Option<Self::Item>;
 }
@@ -109,6 +109,7 @@
     //[migrate]~^ ERROR implementation of `Stream` is not general enough
     //[migrate]~| NOTE  `Stream` would have to be implemented for the type `&'0 mut Map
     //[migrate]~| NOTE  but `Stream` is actually implemented for the type `&'1
+    //[migrate]~| NOTE  implementation of `Stream` is not general enough
     let filter = map.filter(|x: &_| true);
     //[nll]~^ ERROR higher-ranked subtype error
     let count = filter.count(); // Assert that we still have a valid stream.
diff --git a/src/test/ui/hrtb/issue-57639.rs b/src/test/ui/hrtb/issue-57639.rs
index 4bcaef3..392e723 100644
--- a/src/test/ui/hrtb/issue-57639.rs
+++ b/src/test/ui/hrtb/issue-57639.rs
@@ -10,7 +10,7 @@
 //
 // See [this comment on GitHub][c] for more details.
 //
-// run-pass
+// check-pass
 //
 // [c]: https://github.com/rust-lang/rust/issues/57639#issuecomment-455685861
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.rs b/src/test/ui/hygiene/no_implicit_prelude-2018.rs
index 3ad7435..83ca281 100644
--- a/src/test/ui/hygiene/no_implicit_prelude-2018.rs
+++ b/src/test/ui/hygiene/no_implicit_prelude-2018.rs
@@ -4,7 +4,7 @@
 mod bar {
     fn f() {
         ::std::print!(""); // OK
-        print!(); //~ ERROR cannot find macro `print!` in this scope
+        print!(); //~ ERROR cannot find macro `print` in this scope
     }
 }
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
index 0fdb18d..f31b752 100644
--- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `print!` in this scope
+error: cannot find macro `print` in this scope
   --> $DIR/no_implicit_prelude-2018.rs:7:9
    |
 LL |         print!();
diff --git a/src/test/ui/hygiene/no_implicit_prelude.rs b/src/test/ui/hygiene/no_implicit_prelude.rs
index 890c830..204e7b2 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.rs
+++ b/src/test/ui/hygiene/no_implicit_prelude.rs
@@ -13,7 +13,7 @@
     }
     fn f() {
         ::foo::m!();
-        assert_eq!(0, 0); //~ ERROR cannot find macro `panic!` in this scope
+        assert_eq!(0, 0); //~ ERROR cannot find macro `panic` in this scope
     }
 }
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr
index 643f803..bc0ce74 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `panic!` in this scope
+error: cannot find macro `panic` in this scope
   --> $DIR/no_implicit_prelude.rs:16:9
    |
 LL |         assert_eq!(0, 0);
@@ -22,7 +22,7 @@
    |              ------------ in this macro invocation
 ...
 LL |         ().clone()
-   |            ^^^^^
+   |            ^^^^^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr
index 4192b97..39e3252 100644
--- a/src/test/ui/hygiene/trait_items.stderr
+++ b/src/test/ui/hygiene/trait_items.stderr
@@ -5,7 +5,7 @@
    |              ------------ in this macro invocation
 ...
 LL |     pub macro m() { ().f() }
-   |                        ^
+   |                        ^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/if-ret.stderr b/src/test/ui/if-ret.stderr
new file mode 100644
index 0000000..73402e5
--- /dev/null
+++ b/src/test/ui/if-ret.stderr
@@ -0,0 +1,8 @@
+warning: unreachable block in `if` expression
+  --> $DIR/if-ret.rs:6:24
+   |
+LL | fn foo() { if (return) { } }
+   |                        ^^^
+   |
+   = note: `#[warn(unreachable_code)]` on by default
+
diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr
index ad10817..644d26b 100644
--- a/src/test/ui/impl-trait/bindings-opaque.stderr
+++ b/src/test/ui/impl-trait/bindings-opaque.stderr
@@ -10,19 +10,19 @@
   --> $DIR/bindings-opaque.rs:11:17
    |
 LL |     let _ = FOO.count_ones();
-   |                 ^^^^^^^^^^
+   |                 ^^^^^^^^^^ method not found in `impl std::marker::Copy`
 
 error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
   --> $DIR/bindings-opaque.rs:13:17
    |
 LL |     let _ = BAR.count_ones();
-   |                 ^^^^^^^^^^
+   |                 ^^^^^^^^^^ method not found in `impl std::marker::Copy`
 
 error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
   --> $DIR/bindings-opaque.rs:15:17
    |
 LL |     let _ = foo.count_ones();
-   |                 ^^^^^^^^^^
+   |                 ^^^^^^^^^^ method not found in `impl std::marker::Copy`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/impl-trait/closure-calling-parent-fn.rs b/src/test/ui/impl-trait/closure-calling-parent-fn.rs
index 58d7875..9dab334 100644
--- a/src/test/ui/impl-trait/closure-calling-parent-fn.rs
+++ b/src/test/ui/impl-trait/closure-calling-parent-fn.rs
@@ -5,7 +5,7 @@
 // `foo` and hence is treated opaquely within the closure body.  This
 // resulted in a failed subtype relationship.
 //
-// run-pass
+// check-pass
 
 fn foo() -> impl Copy { || foo(); }
 fn bar() -> impl Copy { || bar(); }
diff --git a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr
index 666418f..441191b 100644
--- a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr
+++ b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr
@@ -5,7 +5,7 @@
    | ----------- method `foo` not found for this
 ...
 LL |     f1.foo(1usize);
-   |        ^^^
+   |        ^^^ method not found in `Bar`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `foo`, perhaps you need to implement it:
diff --git a/src/test/ui/impl-trait/issues/issue-53457.rs b/src/test/ui/impl-trait/issues/issue-53457.rs
index de8c579..3f97502 100644
--- a/src/test/ui/impl-trait/issues/issue-53457.rs
+++ b/src/test/ui/impl-trait/issues/issue-53457.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(type_alias_impl_trait)]
 
@@ -9,7 +9,7 @@
 }
 
 fn foo() -> X {
-    bar(|x| ())
+    bar(|_| ())
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
index afb33766..fb870d6 100644
--- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
+++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
@@ -5,7 +5,7 @@
    | ----------- method `is_empty` not found for this
 ...
 LL |     foo(|s| s.is_empty());
-   |               ^^^^^^^^
+   |               ^^^^^^^^ method not found in `Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `is_empty`, perhaps you need to implement it:
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
index 2da3886..3911769 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
@@ -1,5 +1,5 @@
 // edition:2018
-// run-pass
+// check-pass
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
diff --git a/src/test/ui/impl-trait/needs_least_region_or_bound.rs b/src/test/ui/impl-trait/needs_least_region_or_bound.rs
index 52475f6..3c8682b 100644
--- a/src/test/ui/impl-trait/needs_least_region_or_bound.rs
+++ b/src/test/ui/impl-trait/needs_least_region_or_bound.rs
@@ -1,9 +1,7 @@
-// run-pass
+// check-pass
 
 #![feature(member_constraints)]
 
-use std::fmt::Debug;
-
 trait MultiRegionTrait<'a, 'b> {}
 impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {}
 
diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr
index 002b60f..be8f3ab 100644
--- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr
+++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr
@@ -2,7 +2,7 @@
   --> $DIR/no-method-suggested-traits.rs:23:10
    |
 LL |     1u32.method();
-   |          ^^^^^^
+   |          ^^^^^^ method not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
@@ -20,7 +20,7 @@
   --> $DIR/no-method-suggested-traits.rs:26:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method();
-   |                                            ^^^^^^
+   |                                            ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u32>>`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
@@ -38,7 +38,7 @@
   --> $DIR/no-method-suggested-traits.rs:30:9
    |
 LL |     'a'.method();
-   |         ^^^^^^
+   |         ^^^^^^ method not found in `char`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
@@ -58,7 +58,7 @@
    |            the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
 ...
 LL |     std::rc::Rc::new(&mut Box::new(&'a')).method();
-   |                                           ^^^^^^
+   |                                           ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
@@ -70,7 +70,7 @@
   --> $DIR/no-method-suggested-traits.rs:35:10
    |
 LL |     1i32.method();
-   |          ^^^^^^
+   |          ^^^^^^ method not found in `i32`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
@@ -82,7 +82,7 @@
   --> $DIR/no-method-suggested-traits.rs:37:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method();
-   |                                            ^^^^^^
+   |                                            ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
@@ -97,7 +97,7 @@
    | ----------- method `method` not found for this
 ...
 LL |     Foo.method();
-   |         ^^^^^^
+   |         ^^^^^^ method not found in `Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following traits define an item `method`, perhaps you need to implement one of them:
@@ -110,7 +110,7 @@
   --> $DIR/no-method-suggested-traits.rs:42:43
    |
 LL |     std::rc::Rc::new(&mut Box::new(&Foo)).method();
-   |                                           ^^^^^^
+   |                                           ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Foo>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following traits define an item `method`, perhaps you need to implement one of them:
@@ -123,7 +123,7 @@
   --> $DIR/no-method-suggested-traits.rs:45:10
    |
 LL |     1u64.method2();
-   |          ^^^^^^^
+   |          ^^^^^^^ method not found in `u64`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
@@ -133,7 +133,7 @@
   --> $DIR/no-method-suggested-traits.rs:47:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1u64)).method2();
-   |                                            ^^^^^^^
+   |                                            ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u64>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
@@ -143,7 +143,7 @@
   --> $DIR/no-method-suggested-traits.rs:50:37
    |
 LL |     no_method_suggested_traits::Foo.method2();
-   |                                     ^^^^^^^
+   |                                     ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
@@ -153,7 +153,7 @@
   --> $DIR/no-method-suggested-traits.rs:52:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
-   |                                                                       ^^^^^^^
+   |                                                                       ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
@@ -163,7 +163,7 @@
   --> $DIR/no-method-suggested-traits.rs:54:40
    |
 LL |     no_method_suggested_traits::Bar::X.method2();
-   |                                        ^^^^^^^
+   |                                        ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
@@ -173,7 +173,7 @@
   --> $DIR/no-method-suggested-traits.rs:56:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
-   |                                                                          ^^^^^^^
+   |                                                                          ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
@@ -186,7 +186,7 @@
    | ----------- method `method3` not found for this
 ...
 LL |     Foo.method3();
-   |         ^^^^^^^
+   |         ^^^^^^^ method not found in `Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method3`, perhaps you need to implement it:
@@ -196,7 +196,7 @@
   --> $DIR/no-method-suggested-traits.rs:61:43
    |
 LL |     std::rc::Rc::new(&mut Box::new(&Foo)).method3();
-   |                                           ^^^^^^^
+   |                                           ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Foo>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method3`, perhaps you need to implement it:
@@ -209,7 +209,7 @@
    | -------- method `method3` not found for this
 ...
 LL |     Bar::X.method3();
-   |            ^^^^^^^
+   |            ^^^^^^^ method not found in `Bar`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method3`, perhaps you need to implement it:
@@ -219,7 +219,7 @@
   --> $DIR/no-method-suggested-traits.rs:65:46
    |
 LL |     std::rc::Rc::new(&mut Box::new(&Bar::X)).method3();
-   |                                              ^^^^^^^
+   |                                              ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Bar>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `method3`, perhaps you need to implement it:
@@ -229,37 +229,37 @@
   --> $DIR/no-method-suggested-traits.rs:69:13
    |
 LL |     1_usize.method3();
-   |             ^^^^^^^
+   |             ^^^^^^^ method not found in `usize`
 
 error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&usize>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:70:47
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1_usize)).method3();
-   |                                               ^^^^^^^
+   |                                               ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&usize>>`
 
 error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:71:37
    |
 LL |     no_method_suggested_traits::Foo.method3();
-   |                                     ^^^^^^^
+   |                                     ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
 
 error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:72:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
-   |                                                                       ^^^^^^^
+   |                                                                       ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>`
 
 error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:74:40
    |
 LL |     no_method_suggested_traits::Bar::X.method3();
-   |                                        ^^^^^^^
+   |                                        ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
 
 error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:75:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
-   |                                                                          ^^^^^^^
+   |                                                                          ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>`
 
 error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/imports/unresolved-imports-used.rs b/src/test/ui/imports/unresolved-imports-used.rs
index d1461e7..75cf880 100644
--- a/src/test/ui/imports/unresolved-imports-used.rs
+++ b/src/test/ui/imports/unresolved-imports-used.rs
@@ -1,12 +1,18 @@
-// There should be *no* unused import errors.
+// There should be *one* unused import error.
 #![deny(unused_imports)]
 
 mod qux {
    fn quz() {}
+   pub fn quy() {}
 }
 
-use qux::quz; //~ ERROR function `quz` is private
-use qux::bar; //~ ERROR unresolved import `qux::bar`
-use foo::bar; //~ ERROR unresolved import `foo`
+use qux::quz;  //~ ERROR function `quz` is private
+use qux::bar;  //~ ERROR unresolved import `qux::bar`
+use foo::bar;  //~ ERROR unresolved import `foo`
+use baz::*;    //~ ERROR unresolved import `baz`
+use qux::bar2; //~ ERROR unresolved import `qux::bar2`
+use foo2::bar2;//~ ERROR unresolved import `foo2`
+use baz2::*;   //~ ERROR unresolved import `baz2`
+use qux::quy;  //~ ERROR unused import
 
 fn main() {}
diff --git a/src/test/ui/imports/unresolved-imports-used.stderr b/src/test/ui/imports/unresolved-imports-used.stderr
index e8c827a..b341e8e 100644
--- a/src/test/ui/imports/unresolved-imports-used.stderr
+++ b/src/test/ui/imports/unresolved-imports-used.stderr
@@ -1,22 +1,58 @@
 error[E0432]: unresolved import `qux::bar`
-  --> $DIR/unresolved-imports-used.rs:9:5
+  --> $DIR/unresolved-imports-used.rs:10:5
    |
 LL | use qux::bar;
    |     ^^^^^^^^ no `bar` in `qux`
 
+error[E0432]: unresolved import `qux::bar2`
+  --> $DIR/unresolved-imports-used.rs:13:5
+   |
+LL | use qux::bar2;
+   |     ^^^^^^^^^ no `bar2` in `qux`
+
 error[E0432]: unresolved import `foo`
-  --> $DIR/unresolved-imports-used.rs:10:5
+  --> $DIR/unresolved-imports-used.rs:11:5
    |
 LL | use foo::bar;
    |     ^^^ maybe a missing crate `foo`?
 
+error[E0432]: unresolved import `baz`
+  --> $DIR/unresolved-imports-used.rs:12:5
+   |
+LL | use baz::*;
+   |     ^^^ maybe a missing crate `baz`?
+
+error[E0432]: unresolved import `foo2`
+  --> $DIR/unresolved-imports-used.rs:14:5
+   |
+LL | use foo2::bar2;
+   |     ^^^^ maybe a missing crate `foo2`?
+
+error[E0432]: unresolved import `baz2`
+  --> $DIR/unresolved-imports-used.rs:15:5
+   |
+LL | use baz2::*;
+   |     ^^^^ maybe a missing crate `baz2`?
+
 error[E0603]: function `quz` is private
-  --> $DIR/unresolved-imports-used.rs:8:10
+  --> $DIR/unresolved-imports-used.rs:9:10
    |
 LL | use qux::quz;
    |          ^^^
 
-error: aborting due to 3 previous errors
+error: unused import: `qux::quy`
+  --> $DIR/unresolved-imports-used.rs:16:5
+   |
+LL | use qux::quy;
+   |     ^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/unresolved-imports-used.rs:2:9
+   |
+LL | #![deny(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0432, E0603.
 For more information about an error, try `rustc --explain E0432`.
diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr
index 3159a4b..a2ad58a7 100644
--- a/src/test/ui/infinite/infinite-autoderef.stderr
+++ b/src/test/ui/infinite/infinite-autoderef.stderr
@@ -44,7 +44,7 @@
    | ----------- method `bar` not found for this
 ...
 LL |     Foo.bar();
-   |         ^^^
+   |         ^^^ method not found in `Foo`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/intrinsics-always-extern.rs b/src/test/ui/intrinsics-always-extern.rs
new file mode 100644
index 0000000..2295114
--- /dev/null
+++ b/src/test/ui/intrinsics-always-extern.rs
@@ -0,0 +1,16 @@
+#![feature(intrinsics)]
+
+trait Foo {
+    extern "rust-intrinsic" fn foo(&self); //~ ERROR intrinsic must
+}
+
+impl Foo for () {
+    extern "rust-intrinsic" fn foo(&self) { //~ ERROR intrinsic must
+    }
+}
+
+extern "rust-intrinsic" fn hello() {//~ ERROR intrinsic must
+}
+
+fn main() {
+}
diff --git a/src/test/ui/intrinsics-always-extern.stderr b/src/test/ui/intrinsics-always-extern.stderr
new file mode 100644
index 0000000..24b6da1
--- /dev/null
+++ b/src/test/ui/intrinsics-always-extern.stderr
@@ -0,0 +1,24 @@
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/intrinsics-always-extern.rs:4:32
+   |
+LL |     extern "rust-intrinsic" fn foo(&self);
+   |                                ^^^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/intrinsics-always-extern.rs:8:43
+   |
+LL |       extern "rust-intrinsic" fn foo(&self) {
+   |  ___________________________________________^
+LL | |     }
+   | |_____^
+
+error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
+  --> $DIR/intrinsics-always-extern.rs:12:36
+   |
+LL |   extern "rust-intrinsic" fn hello() {
+   |  ____________________________________^
+LL | | }
+   | |_^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/issues/issue-10465.stderr b/src/test/ui/issues/issue-10465.stderr
index 6efbd8e..413daa6 100644
--- a/src/test/ui/issues/issue-10465.stderr
+++ b/src/test/ui/issues/issue-10465.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-10465.rs:17:15
    |
 LL |             b.foo();
-   |               ^^^
+   |               ^^^ method not found in `&b::B`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/issues/issue-11692-1.rs b/src/test/ui/issues/issue-11692-1.rs
index 70b712c..b6f3bb8 100644
--- a/src/test/ui/issues/issue-11692-1.rs
+++ b/src/test/ui/issues/issue-11692-1.rs
@@ -1,3 +1,3 @@
 fn main() {
-    print!(testo!()); //~ ERROR cannot find macro `testo!` in this scope
+    print!(testo!()); //~ ERROR cannot find macro `testo` in this scope
 }
diff --git a/src/test/ui/issues/issue-11692-1.stderr b/src/test/ui/issues/issue-11692-1.stderr
index bfd1647..3864634 100644
--- a/src/test/ui/issues/issue-11692-1.stderr
+++ b/src/test/ui/issues/issue-11692-1.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `testo!` in this scope
+error: cannot find macro `testo` in this scope
   --> $DIR/issue-11692-1.rs:2:12
    |
 LL |     print!(testo!());
diff --git a/src/test/ui/issues/issue-11692-2.rs b/src/test/ui/issues/issue-11692-2.rs
index 61be284..5957ed3 100644
--- a/src/test/ui/issues/issue-11692-2.rs
+++ b/src/test/ui/issues/issue-11692-2.rs
@@ -1,3 +1,3 @@
 fn main() {
-    concat!(test!()); //~ ERROR cannot find macro `test!` in this scope
+    concat!(test!()); //~ ERROR cannot find macro `test` in this scope
 }
diff --git a/src/test/ui/issues/issue-11692-2.stderr b/src/test/ui/issues/issue-11692-2.stderr
index 740c355..f021943 100644
--- a/src/test/ui/issues/issue-11692-2.stderr
+++ b/src/test/ui/issues/issue-11692-2.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `test!` in this scope
+error: cannot find macro `test` in this scope
   --> $DIR/issue-11692-2.rs:2:13
    |
 LL |     concat!(test!());
diff --git a/src/test/ui/issues/issue-1251.rs b/src/test/ui/issues/issue-1251.rs
index 63b5a4d..77278ec 100644
--- a/src/test/ui/issues/issue-1251.rs
+++ b/src/test/ui/issues/issue-1251.rs
@@ -6,8 +6,6 @@
 
 #![feature(rustc_private)]
 
-#![crate_id="rust_get_test_int"]
-
 mod rustrt {
     extern crate libc;
 
diff --git a/src/test/ui/issues/issue-13853.stderr b/src/test/ui/issues/issue-13853.stderr
index 9026845..c57ca3e 100644
--- a/src/test/ui/issues/issue-13853.stderr
+++ b/src/test/ui/issues/issue-13853.stderr
@@ -14,7 +14,7 @@
   --> $DIR/issue-13853.rs:27:23
    |
 LL |     for node in graph.iter() {
-   |                       ^^^^
+   |                       ^^^^ method not found in `&G`
 
 error[E0308]: mismatched types
   --> $DIR/issue-13853.rs:37:13
diff --git a/src/test/ui/issues/issue-14309.rs b/src/test/ui/issues/issue-14309.rs
index d0e532a..328a4c9 100644
--- a/src/test/ui/issues/issue-14309.rs
+++ b/src/test/ui/issues/issue-14309.rs
@@ -27,7 +27,7 @@
 }
 
 extern "C" {
-    fn foo(x: A); //~ ERROR type `A` which is not FFI-safe
+    fn foo(x: A); //~ ERROR type `A`, which is not FFI-safe
     fn bar(x: B); //~ ERROR type `A`
     fn baz(x: C);
     fn qux(x: A2); //~ ERROR type `A`
diff --git a/src/test/ui/issues/issue-14309.stderr b/src/test/ui/issues/issue-14309.stderr
index e049109..f598e1f 100644
--- a/src/test/ui/issues/issue-14309.stderr
+++ b/src/test/ui/issues/issue-14309.stderr
@@ -1,8 +1,8 @@
-error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `A`, which is not FFI-safe
   --> $DIR/issue-14309.rs:30:15
    |
 LL |     fn foo(x: A);
-   |               ^
+   |               ^ not FFI-safe
    |
 note: lint level defined here
   --> $DIR/issue-14309.rs:1:9
@@ -10,6 +10,7 @@
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -18,13 +19,14 @@
 LL | | }
    | |_^
 
-error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `A`, which is not FFI-safe
   --> $DIR/issue-14309.rs:31:15
    |
 LL |     fn bar(x: B);
-   |               ^
+   |               ^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -33,13 +35,14 @@
 LL | | }
    | |_^
 
-error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `A`, which is not FFI-safe
   --> $DIR/issue-14309.rs:33:15
    |
 LL |     fn qux(x: A2);
-   |               ^^
+   |               ^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -48,13 +51,14 @@
 LL | | }
    | |_^
 
-error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `A`, which is not FFI-safe
   --> $DIR/issue-14309.rs:34:16
    |
 LL |     fn quux(x: B2);
-   |                ^^
+   |                ^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -63,13 +67,14 @@
 LL | | }
    | |_^
 
-error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `A`, which is not FFI-safe
   --> $DIR/issue-14309.rs:36:16
    |
 LL |     fn fred(x: D);
-   |                ^
+   |                ^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
diff --git a/src/test/ui/issues/issue-15207.stderr b/src/test/ui/issues/issue-15207.stderr
index 2d90eb8..25ce7cb 100644
--- a/src/test/ui/issues/issue-15207.stderr
+++ b/src/test/ui/issues/issue-15207.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-15207.rs:3:15
    |
 LL |         break.push(1)
-   |               ^^^^
+   |               ^^^^ method not found in `!`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-15381.rs b/src/test/ui/issues/issue-15381.rs
index 4c8e1b4..5307153 100644
--- a/src/test/ui/issues/issue-15381.rs
+++ b/src/test/ui/issues/issue-15381.rs
@@ -2,7 +2,7 @@
     let values: Vec<u8> = vec![1,2,3,4,5,6,7,8];
 
     for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
-        //~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered
+        //~^ ERROR refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not
         println!("y={}", y);
         //~^ ERROR borrow of possibly-uninitialized variable: `y`
     }
diff --git a/src/test/ui/issues/issue-15381.stderr b/src/test/ui/issues/issue-15381.stderr
index e810605..47a0d51 100644
--- a/src/test/ui/issues/issue-15381.stderr
+++ b/src/test/ui/issues/issue-15381.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in `for` loop binding: `&[]` not covered
+error[E0005]: refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
   --> $DIR/issue-15381.rs:4:9
    |
 LL |     for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
-   |         ^^^^^^^^ pattern `&[]` not covered
+   |         ^^^^^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
 
 error[E0381]: borrow of possibly-uninitialized variable: `y`
   --> $DIR/issue-15381.rs:6:26
diff --git a/src/test/ui/issues/issue-16250.rs b/src/test/ui/issues/issue-16250.rs
index bf01627..a3c6751 100644
--- a/src/test/ui/issues/issue-16250.rs
+++ b/src/test/ui/issues/issue-16250.rs
@@ -3,7 +3,7 @@
 pub struct Foo;
 
 extern {
-    pub fn foo(x: (Foo)); //~ ERROR unspecified layout
+    pub fn foo(x: (Foo)); //~ ERROR `extern` block uses type `Foo`
 }
 
 fn main() {
diff --git a/src/test/ui/issues/issue-16250.stderr b/src/test/ui/issues/issue-16250.stderr
index f3686e8..5686ac3 100644
--- a/src/test/ui/issues/issue-16250.stderr
+++ b/src/test/ui/issues/issue-16250.stderr
@@ -1,8 +1,8 @@
-error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `Foo`, which is not FFI-safe
   --> $DIR/issue-16250.rs:6:20
    |
 LL |     pub fn foo(x: (Foo));
-   |                    ^^^
+   |                    ^^^ not FFI-safe
    |
 note: lint level defined here
   --> $DIR/issue-16250.rs:1:9
@@ -11,6 +11,7 @@
    |         ^^^^^^^^
    = note: `#[deny(improper_ctypes)]` implied by `#[deny(warnings)]`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/issue-16250.rs:3:1
    |
diff --git a/src/test/ui/issues/issue-1871.stderr b/src/test/ui/issues/issue-1871.stderr
index fecd689..b774ca2 100644
--- a/src/test/ui/issues/issue-1871.stderr
+++ b/src/test/ui/issues/issue-1871.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-1871.rs:7:9
    |
 LL |       f.honk()
-   |         ^^^^
+   |         ^^^^ method not found in `{integer}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19521.stderr b/src/test/ui/issues/issue-19521.stderr
index a43368b..c15c539 100644
--- a/src/test/ui/issues/issue-19521.stderr
+++ b/src/test/ui/issues/issue-19521.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-19521.rs:2:8
    |
 LL |     "".homura()();
-   |        ^^^^^^
+   |        ^^^^^^ method not found in `&'static str`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19692.stderr b/src/test/ui/issues/issue-19692.stderr
index 5e576f1..fe920c1 100644
--- a/src/test/ui/issues/issue-19692.stderr
+++ b/src/test/ui/issues/issue-19692.stderr
@@ -5,7 +5,7 @@
    | -------------- method `kaname` not found for this
 ...
 LL |     let Some(ref madoka) = Some(homura.kaname());
-   |                                        ^^^^^^
+   |                                        ^^^^^^ method not found in `Homura`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19734.rs b/src/test/ui/issues/issue-19734.rs
index b730e19..fe4a327 100644
--- a/src/test/ui/issues/issue-19734.rs
+++ b/src/test/ui/issues/issue-19734.rs
@@ -4,5 +4,5 @@
 
 impl Type {
     undef!();
-    //~^ ERROR cannot find macro `undef!` in this scope
+    //~^ ERROR cannot find macro `undef` in this scope
 }
diff --git a/src/test/ui/issues/issue-19734.stderr b/src/test/ui/issues/issue-19734.stderr
index fc1a7d0..8175797 100644
--- a/src/test/ui/issues/issue-19734.stderr
+++ b/src/test/ui/issues/issue-19734.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `undef!` in this scope
+error: cannot find macro `undef` in this scope
   --> $DIR/issue-19734.rs:6:5
    |
 LL |     undef!();
diff --git a/src/test/ui/issues/issue-2149.stderr b/src/test/ui/issues/issue-2149.stderr
index 1df32aa..8ce2ba0 100644
--- a/src/test/ui/issues/issue-2149.stderr
+++ b/src/test/ui/issues/issue-2149.stderr
@@ -10,7 +10,7 @@
   --> $DIR/issue-2149.rs:13:12
    |
 LL |     ["hi"].bind(|x| [x] );
-   |            ^^^^
+   |            ^^^^ method not found in `[&str; 1]`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `bind`, perhaps you need to implement it:
diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr
index 8e4e09b..4e5cace 100644
--- a/src/test/ui/issues/issue-21596.stderr
+++ b/src/test/ui/issues/issue-21596.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-21596.rs:4:22
    |
 LL |     println!("{}", z.to_string());
-   |                      ^^^^^^^^^
+   |                      ^^^^^^^^^ method not found in `*const u8`
    |
    = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
    = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
diff --git a/src/test/ui/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs b/src/test/ui/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs
index 48362d0..7253d35 100644
--- a/src/test/ui/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs
+++ b/src/test/ui/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs
@@ -5,8 +5,6 @@
 // See further discussion on rust-lang/rust#24535,
 // rust-lang/rfcs#1006, and rust-lang/rfcs#107
 
-#![feature(bind_by_move_pattern_guards)]
-
 fn main() {
     rust_issue_24535();
     rfcs_issue_1006_1();
diff --git a/src/test/ui/issues/issue-25385.stderr b/src/test/ui/issues/issue-25385.stderr
index e170a9d..ab4db7e 100644
--- a/src/test/ui/issues/issue-25385.stderr
+++ b/src/test/ui/issues/issue-25385.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-25385.rs:2:23
    |
 LL |     ($e:expr) => { $e.foo() }
-   |                       ^^^
+   |                       ^^^ method not found in `i32`
 ...
 LL |     foo!(a);
    |     -------- in this macro invocation
@@ -11,7 +11,7 @@
   --> $DIR/issue-25385.rs:10:15
    |
 LL |     foo!(1i32.foo());
-   |               ^^^
+   |               ^^^ method not found in `i32`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-26448-2.rs b/src/test/ui/issues/issue-26448-2.rs
index 17e7c1f..c60e06c 100644
--- a/src/test/ui/issues/issue-26448-2.rs
+++ b/src/test/ui/issues/issue-26448-2.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 pub struct Bar<T> {
     items: Vec<&'static str>,
diff --git a/src/test/ui/issues/issue-26448-3.rs b/src/test/ui/issues/issue-26448-3.rs
index e57352e..d48022c 100644
--- a/src/test/ui/issues/issue-26448-3.rs
+++ b/src/test/ui/issues/issue-26448-3.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 pub struct Item {
     _inner: &'static str,
diff --git a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs
index 1ffb7f6..82d8b9e 100644
--- a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs
+++ b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs
@@ -5,8 +5,6 @@
 // reject it. But I want to make sure that we continue to reject it
 // (under NLL) even when that conservaive check goes away.
 
-#![feature(bind_by_move_pattern_guards)]
-
 fn main() {
     let mut b = &mut true;
     match b {
diff --git a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr
index a8eb78b..f0264b5 100644
--- a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr
+++ b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
-  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
    |
 LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |                         ^^                   - mutable borrow occurs due to use of `r` in closure
diff --git a/src/test/ui/issues/issue-27697.rs b/src/test/ui/issues/issue-27697.rs
index 8307001..12af8a8 100644
--- a/src/test/ui/issues/issue-27697.rs
+++ b/src/test/ui/issues/issue-27697.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 use std::ops::Deref;
 
diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr
index 4c1dfb8..c9ede03 100644
--- a/src/test/ui/issues/issue-2823.stderr
+++ b/src/test/ui/issues/issue-2823.stderr
@@ -5,7 +5,7 @@
    | -------- method `clone` not found for this
 ...
 LL |     let _d = c.clone();
-   |                ^^^^^
+   |                ^^^^^ method not found in `C`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
diff --git a/src/test/ui/issues/issue-29124.stderr b/src/test/ui/issues/issue-29124.stderr
index 3beb728..c537c61 100644
--- a/src/test/ui/issues/issue-29124.stderr
+++ b/src/test/ui/issues/issue-29124.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-29124.rs:15:15
    |
 LL |     Obj::func.x();
-   |               ^
+   |               ^ method not found in `fn() -> Ret {Obj::func}`
    |
    = note: Obj::func is a function, perhaps you wish to call it
 
@@ -10,7 +10,7 @@
   --> $DIR/issue-29124.rs:17:10
    |
 LL |     func.x();
-   |          ^
+   |          ^ method not found in `fn() -> Ret {func}`
    |
    = note: func is a function, perhaps you wish to call it
 
diff --git a/src/test/ui/issues/issue-29181.stderr b/src/test/ui/issues/issue-29181.stderr
index 0920142..250b158 100644
--- a/src/test/ui/issues/issue-29181.stderr
+++ b/src/test/ui/issues/issue-29181.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-29181.rs:6:7
    |
 LL |     0.homura();
-   |       ^^^^^^
+   |       ^^^^^^ method not found in `{integer}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr
index 3ca8338..6d03b78 100644
--- a/src/test/ui/issues/issue-31173.stderr
+++ b/src/test/ui/issues/issue-31173.stderr
@@ -11,7 +11,7 @@
   --> $DIR/issue-31173.rs:14:10
    |
 LL |         .collect();
-   |          ^^^^^^^
+   |          ^^^^^^^ method not found in `std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>`
    |
    = note: the method `collect` exists but the following trait bounds were not satisfied:
            `&mut std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>> : std::iter::Iterator`
diff --git a/src/test/ui/issues/issue-31561.rs b/src/test/ui/issues/issue-31561.rs
index 87b19fe5..813b240 100644
--- a/src/test/ui/issues/issue-31561.rs
+++ b/src/test/ui/issues/issue-31561.rs
@@ -6,5 +6,5 @@
 
 fn main() {
     let Thing::Foo(y) = Thing::Foo(1);
-    //~^ ERROR refutable pattern in local binding: `Bar` not covered
+    //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered
 }
diff --git a/src/test/ui/issues/issue-31561.stderr b/src/test/ui/issues/issue-31561.stderr
index 246137a..9ec26b0 100644
--- a/src/test/ui/issues/issue-31561.stderr
+++ b/src/test/ui/issues/issue-31561.stderr
@@ -1,15 +1,17 @@
-error[E0005]: refutable pattern in local binding: `Bar` not covered
+error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
   --> $DIR/issue-31561.rs:8:9
    |
 LL | / enum Thing {
 LL | |     Foo(u8),
 LL | |     Bar,
+   | |     --- not covered
 LL | |     Baz
+   | |     --- not covered
 LL | | }
    | |_- `Thing` defined here
 ...
 LL |       let Thing::Foo(y) = Thing::Foo(1);
-   |           ^^^^^^^^^^^^^ pattern `Bar` not covered
+   |           ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-32655.rs b/src/test/ui/issues/issue-32655.rs
index fad7bf5..f52e092 100644
--- a/src/test/ui/issues/issue-32655.rs
+++ b/src/test/ui/issues/issue-32655.rs
@@ -1,6 +1,6 @@
 macro_rules! foo (
     () => (
-        #[derive_Clone] //~ ERROR cannot find attribute macro `derive_Clone` in this scope
+        #[derive_Clone] //~ ERROR cannot find attribute `derive_Clone` in this scope
         struct T;
     );
 );
@@ -12,7 +12,7 @@
 foo!();
 
 bar!(
-    #[derive_Clone] //~ ERROR cannot find attribute macro `derive_Clone` in this scope
+    #[derive_Clone] //~ ERROR cannot find attribute `derive_Clone` in this scope
     struct S;
 );
 
diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr
index e13bed0..ca085b2 100644
--- a/src/test/ui/issues/issue-32655.stderr
+++ b/src/test/ui/issues/issue-32655.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `derive_Clone` in this scope
+error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:3:11
    |
 LL |         #[derive_Clone]
@@ -7,7 +7,7 @@
 LL | foo!();
    | ------- in this macro invocation
 
-error: cannot find attribute macro `derive_Clone` in this scope
+error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:15:7
    |
 LL |     #[derive_Clone]
diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr
index 7f89caf..8d52e08 100644
--- a/src/test/ui/issues/issue-34334.stderr
+++ b/src/test/ui/issues/issue-34334.stderr
@@ -45,7 +45,7 @@
   --> $DIR/issue-34334.rs:9:36
    |
 LL |     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
-   |                                    ^^^^
+   |                                    ^^^^ method not found in `()`
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr
index 99d99db..b381203 100644
--- a/src/test/ui/issues/issue-35677.stderr
+++ b/src/test/ui/issues/issue-35677.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-35677.rs:4:10
    |
 LL |     this.is_subset(other)
-   |          ^^^^^^^^^
+   |          ^^^^^^^^^ method not found in `&std::collections::HashSet<T>`
    |
    = note: the method `is_subset` exists but the following trait bounds were not satisfied:
            `T : std::cmp::Eq`
diff --git a/src/test/ui/issues/issue-36836.rs b/src/test/ui/issues/issue-36836.rs
new file mode 100644
index 0000000..99c5621
--- /dev/null
+++ b/src/test/ui/issues/issue-36836.rs
@@ -0,0 +1,15 @@
+// Previously, in addition to the real cause of the problem as seen below,
+// the compiler would tell the user:
+//
+// ```
+// error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or
+// predicates
+// ```
+//
+// With this test, we check that only the relevant error is emitted.
+
+trait Foo {}
+
+impl<T> Foo for Bar<T> {} //~ ERROR cannot find type `Bar` in this scope
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-36836.stderr b/src/test/ui/issues/issue-36836.stderr
new file mode 100644
index 0000000..418194f
--- /dev/null
+++ b/src/test/ui/issues/issue-36836.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Bar` in this scope
+  --> $DIR/issue-36836.rs:13:17
+   |
+LL | impl<T> Foo for Bar<T> {}
+   |                 ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/issues/issue-38591.rs b/src/test/ui/issues/issue-38591.rs
index 7aa71f8..2f594b4 100644
--- a/src/test/ui/issues/issue-38591.rs
+++ b/src/test/ui/issues/issue-38591.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 struct S<T> {
     t : T,
diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr
index 108c969..66680b9 100644
--- a/src/test/ui/issues/issue-39175.stderr
+++ b/src/test/ui/issues/issue-39175.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-39175.rs:15:39
    |
 LL |     Command::new("echo").arg("hello").exec();
-   |                                       ^^^^
+   |                                       ^^^^ method not found in `&mut std::process::Command`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/issues/issue-40845.rs b/src/test/ui/issues/issue-40845.rs
index c9102f4..a4ede6a 100644
--- a/src/test/ui/issues/issue-40845.rs
+++ b/src/test/ui/issues/issue-40845.rs
@@ -1,6 +1,6 @@
-trait T { m!(); } //~ ERROR cannot find macro `m!` in this scope
+trait T { m!(); } //~ ERROR cannot find macro `m` in this scope
 
 struct S;
-impl S { m!(); } //~ ERROR cannot find macro `m!` in this scope
+impl S { m!(); } //~ ERROR cannot find macro `m` in this scope
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-40845.stderr b/src/test/ui/issues/issue-40845.stderr
index a8be38e..2744330 100644
--- a/src/test/ui/issues/issue-40845.stderr
+++ b/src/test/ui/issues/issue-40845.stderr
@@ -1,10 +1,10 @@
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/issue-40845.rs:4:10
    |
 LL | impl S { m!(); }
    |          ^
 
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/issue-40845.rs:1:11
    |
 LL | trait T { m!(); }
diff --git a/src/test/ui/issues/issue-41880.stderr b/src/test/ui/issues/issue-41880.stderr
index 359a234..0e1d55c 100644
--- a/src/test/ui/issues/issue-41880.stderr
+++ b/src/test/ui/issues/issue-41880.stderr
@@ -5,7 +5,7 @@
    | ------------------------ method `iter` not found for this
 ...
 LL |     println!("{:?}", a.iter().take(10).collect::<Vec<usize>>());
-   |                        ^^^^
+   |                        ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-43189.stderr b/src/test/ui/issues/issue-43189.stderr
index e364650..33c3f18 100644
--- a/src/test/ui/issues/issue-43189.stderr
+++ b/src/test/ui/issues/issue-43189.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-43189.rs:10:8
    |
 LL |     ().a();
-   |        ^
+   |        ^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/issues/issue-43806.rs b/src/test/ui/issues/issue-43806.rs
index cbfbfa3..8c8cccf 100644
--- a/src/test/ui/issues/issue-43806.rs
+++ b/src/test/ui/issues/issue-43806.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![deny(unused_results)]
 
diff --git a/src/test/ui/issues/issue-44415.stderr b/src/test/ui/issues/issue-44415.stderr
deleted file mode 100644
index 8008e53..0000000
--- a/src/test/ui/issues/issue-44415.stderr
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0`
-  --> $DIR/issue-44415.rs:6:17
-   |
-LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
-   |
-note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`...
-  --> $DIR/issue-44415.rs:6:17
-   |
-LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
-note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`...
-  --> $DIR/issue-44415.rs:6:26
-   |
-LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing layout of `Foo`...
-   = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
-   = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
-note: cycle used when processing `Foo`
-  --> $DIR/issue-44415.rs:5:1
-   |
-LL | struct Foo {
-   | ^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/issues/issue-46101.rs b/src/test/ui/issues/issue-46101.rs
index 2d9111e..8b1343b 100644
--- a/src/test/ui/issues/issue-46101.rs
+++ b/src/test/ui/issues/issue-46101.rs
@@ -2,3 +2,5 @@
 trait Foo {}
 #[derive(Foo::Anything)] //~ ERROR failed to resolve: partially resolved path in a derive macro
 struct S;
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-46101.stderr b/src/test/ui/issues/issue-46101.stderr
index 772d4bf..9c88d3b 100644
--- a/src/test/ui/issues/issue-46101.stderr
+++ b/src/test/ui/issues/issue-46101.stderr
@@ -4,11 +4,6 @@
 LL | #[derive(Foo::Anything)]
    |          ^^^^^^^^^^^^^ partially resolved path in a derive macro
 
-error[E0601]: `main` function not found in crate `issue_46101`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-46101.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0433, E0601.
-For more information about an error, try `rustc --explain E0433`.
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/issues/issue-48132.rs b/src/test/ui/issues/issue-48132.rs
index ea325ea..f564aef 100644
--- a/src/test/ui/issues/issue-48132.rs
+++ b/src/test/ui/issues/issue-48132.rs
@@ -3,6 +3,8 @@
 
 // run-pass
 
+#![allow(dead_code)]
+
 struct Inner<I, V> {
     iterator: I,
     item: V,
diff --git a/src/test/ui/issues/issue-48179.rs b/src/test/ui/issues/issue-48179.rs
index 90e9858..f81203d 100644
--- a/src/test/ui/issues/issue-48179.rs
+++ b/src/test/ui/issues/issue-48179.rs
@@ -1,7 +1,7 @@
 // Regression test for #48132. This was failing due to problems around
 // the projection caching and dropck type enumeration.
 
-// run-pass
+// check-pass
 
 pub struct Container<T: Iterator> {
     value: Option<T::Item>,
diff --git a/src/test/ui/issues/issue-49040.rs b/src/test/ui/issues/issue-49040.rs
index a5f05d2..b7a541d 100644
--- a/src/test/ui/issues/issue-49040.rs
+++ b/src/test/ui/issues/issue-49040.rs
@@ -1,2 +1,3 @@
 #![allow(unused_variables)]; //~ ERROR expected item, found `;`
+//~^ ERROR `main` function
 fn foo() {}
diff --git a/src/test/ui/issues/issue-49040.stderr b/src/test/ui/issues/issue-49040.stderr
index de78b8d..4134d6a 100644
--- a/src/test/ui/issues/issue-49040.stderr
+++ b/src/test/ui/issues/issue-49040.stderr
@@ -5,8 +5,12 @@
    |                            ^ help: remove this semicolon
 
 error[E0601]: `main` function not found in crate `issue_49040`
+  --> $DIR/issue-49040.rs:1:1
    |
-   = note: consider adding a `main` function to `$DIR/issue-49040.rs`
+LL | / #![allow(unused_variables)];
+LL | |
+LL | | fn foo() {}
+   | |__^ consider adding a `main` function to `$DIR/issue-49040.rs`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-49074.rs b/src/test/ui/issues/issue-49074.rs
index 38074d5..752bb34 100644
--- a/src/test/ui/issues/issue-49074.rs
+++ b/src/test/ui/issues/issue-49074.rs
@@ -1,7 +1,7 @@
 // Check that unknown attribute error is shown even if there are unresolved macros.
 
 #[marco_use] // typo
-//~^ ERROR cannot find attribute macro `marco_use` in this scope
+//~^ ERROR cannot find attribute `marco_use` in this scope
 mod foo {
     macro_rules! bar {
         () => ();
@@ -9,5 +9,5 @@
 }
 
 fn main() {
-   bar!(); //~ ERROR cannot find macro `bar!` in this scope
+   bar!(); //~ ERROR cannot find macro `bar` in this scope
 }
diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/issues/issue-49074.stderr
index e0d3bb3..bbfeb4e 100644
--- a/src/test/ui/issues/issue-49074.stderr
+++ b/src/test/ui/issues/issue-49074.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `bar!` in this scope
+error: cannot find macro `bar` in this scope
   --> $DIR/issue-49074.rs:12:4
    |
 LL |    bar!();
@@ -6,7 +6,7 @@
    |
    = help: have you added the `#[macro_use]` on the module/import?
 
-error: cannot find attribute macro `marco_use` in this scope
+error: cannot find attribute `marco_use` in this scope
   --> $DIR/issue-49074.rs:3:3
    |
 LL | #[marco_use] // typo
diff --git a/src/test/ui/issues/issue-49934-errors.rs b/src/test/ui/issues/issue-49934-errors.rs
new file mode 100644
index 0000000..6fa5f01
--- /dev/null
+++ b/src/test/ui/issues/issue-49934-errors.rs
@@ -0,0 +1,13 @@
+fn foo<#[derive(Debug)] T>() {
+//~^ ERROR `derive` may only be applied to structs, enums and unions
+//~| ERROR expected an inert attribute, found a derive macro
+    match 0 {
+        #[derive(Debug)]
+        //~^ ERROR `derive` may only be applied to structs, enums and unions
+        //~| ERROR expected an inert attribute, found a derive macro
+        _ => (),
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr
new file mode 100644
index 0000000..8778d88
--- /dev/null
+++ b/src/test/ui/issues/issue-49934-errors.stderr
@@ -0,0 +1,26 @@
+error: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-49934-errors.rs:1:8
+   |
+LL | fn foo<#[derive(Debug)] T>() {
+   |        ^^^^^^^^^^^^^^^^
+
+error: expected an inert attribute, found a derive macro
+  --> $DIR/issue-49934-errors.rs:1:17
+   |
+LL | fn foo<#[derive(Debug)] T>() {
+   |                 ^^^^^
+
+error: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-49934-errors.rs:5:9
+   |
+LL |         #[derive(Debug)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: expected an inert attribute, found a derive macro
+  --> $DIR/issue-49934-errors.rs:5:18
+   |
+LL |         #[derive(Debug)]
+   |                  ^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/issues/issue-49934.rs b/src/test/ui/issues/issue-49934.rs
index e75381a..262f493 100644
--- a/src/test/ui/issues/issue-49934.rs
+++ b/src/test/ui/issues/issue-49934.rs
@@ -1,15 +1,8 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(stmt_expr_attributes)]
 #![warn(unused_attributes)] //~ NOTE lint level defined here
 
-fn foo<#[derive(Debug)] T>() { //~ WARN unused attribute
-    match 0 {
-        #[derive(Debug)] //~ WARN unused attribute
-        _ => (),
-    }
-}
-
 fn main() {
     // fold_stmt (Item)
     #[allow(dead_code)]
diff --git a/src/test/ui/issues/issue-49934.stderr b/src/test/ui/issues/issue-49934.stderr
index 6ca751a..dbec379e3 100644
--- a/src/test/ui/issues/issue-49934.stderr
+++ b/src/test/ui/issues/issue-49934.stderr
@@ -1,5 +1,5 @@
 warning: `#[derive]` does nothing on macro invocations
-  --> $DIR/issue-49934.rs:20:5
+  --> $DIR/issue-49934.rs:13:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
@@ -7,10 +7,10 @@
    = note: this may become a hard error in a future release
 
 warning: unused attribute
-  --> $DIR/issue-49934.rs:6:8
+  --> $DIR/issue-49934.rs:19:5
    |
-LL | fn foo<#[derive(Debug)] T>() {
-   |        ^^^^^^^^^^^^^^^^
+LL |     #[derive(Debug)]
+   |     ^^^^^^^^^^^^^^^^
    |
 note: lint level defined here
   --> $DIR/issue-49934.rs:4:9
@@ -19,31 +19,19 @@
    |         ^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-49934.rs:8:9
-   |
-LL |         #[derive(Debug)]
-   |         ^^^^^^^^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-49934.rs:26:5
+  --> $DIR/issue-49934.rs:23:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-49934.rs:30:5
-   |
-LL |     #[derive(Debug)]
-   |     ^^^^^^^^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-49934.rs:34:13
+  --> $DIR/issue-49934.rs:27:13
    |
 LL |     let _ = #[derive(Debug)] "Hello, world!";
    |             ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-49934.rs:39:9
+  --> $DIR/issue-49934.rs:32:9
    |
 LL |         #[derive(Debug)]
    |         ^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr
index 2c3a18b..29fd15f 100644
--- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr
+++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr
@@ -2,7 +2,7 @@
   --> $DIR/option-as_deref_mut.rs:4:33
    |
 LL |     let _result = &mut Some(42).as_deref_mut();
-   |                                 ^^^^^^^^^^^^
+   |                                 ^^^^^^^^^^^^ method not found in `std::option::Option<{integer}>`
    |
    = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied:
            `{integer} : std::ops::DerefMut`
diff --git a/src/test/ui/issues/issue-5153.stderr b/src/test/ui/issues/issue-5153.stderr
index 97214fb..5034e6d 100644
--- a/src/test/ui/issues/issue-5153.stderr
+++ b/src/test/ui/issues/issue-5153.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-5153.rs:10:27
    |
 LL |     (&5isize as &dyn Foo).foo();
-   |                           ^^^
+   |                           ^^^ method not found in `&dyn Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `foo`, perhaps you need to implement it:
diff --git a/src/test/ui/issues/issue-54062.stderr b/src/test/ui/issues/issue-54062.stderr
index 082ac91..3830ad4 100644
--- a/src/test/ui/issues/issue-54062.stderr
+++ b/src/test/ui/issues/issue-54062.stderr
@@ -8,7 +8,7 @@
   --> $DIR/issue-54062.rs:10:37
    |
 LL |     let _ = test.comps.inner.lock().unwrap();
-   |                                     ^^^^^^
+   |                                     ^^^^^^ method not found in `std::sys_common::mutex::MutexGuard<'_>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-54302-cases.stderr b/src/test/ui/issues/issue-54302-cases.stderr
index 9863761..3ed2779 100644
--- a/src/test/ui/issues/issue-54302-cases.stderr
+++ b/src/test/ui/issues/issue-54302-cases.stderr
@@ -1,38 +1,58 @@
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:63:5
    |
-LL |     <u32 as RefFoo<u32>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | |     fn foo(self) -> &'x T;
+LL | | }
+   | |_- trait `Foo` defined here
+...
+LL |       <u32 as RefFoo<u32>>::ref_foo(a)
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`
-   = note: but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
+   = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:69:5
    |
-LL |     <i32 as RefFoo<i32>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | |     fn foo(self) -> &'x T;
+LL | | }
+   | |_- trait `Foo` defined here
+...
+LL |       <i32 as RefFoo<i32>>::ref_foo(a)
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`
-   = note: but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
+   = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
 
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:75:5
    |
-LL |     <u64 as RefFoo<u64>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | |     fn foo(self) -> &'x T;
+LL | | }
+   | |_- trait `Foo` defined here
+...
+LL |       <u64 as RefFoo<u64>>::ref_foo(a)
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`
-   = note: but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
+   = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
 
 error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:81:5
    |
-LL |     <i64 as RefFoo<i64>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | |     fn foo(self) -> &'x T;
+LL | | }
+   | |_- trait `Foo` defined here
+...
+LL |       <i64 as RefFoo<i64>>::ref_foo(a)
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`
-   = note: but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
+   = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-54302.stderr b/src/test/ui/issues/issue-54302.stderr
index c6d0805..1b3f57b 100644
--- a/src/test/ui/issues/issue-54302.stderr
+++ b/src/test/ui/issues/issue-54302.stderr
@@ -1,11 +1,14 @@
 error: implementation of `Deserialize` is not general enough
   --> $DIR/issue-54302.rs:13:5
    |
+LL | trait Deserialize<'de> {}
+   | ------------------------- trait `Deserialize` defined here
+...
 LL |     assert_deserialize_owned::<&'static str>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
    |
-   = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`
-   = note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
+   = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`...
+   = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-55731.stderr b/src/test/ui/issues/issue-55731.stderr
index f25e18e..f44c842 100644
--- a/src/test/ui/issues/issue-55731.stderr
+++ b/src/test/ui/issues/issue-55731.stderr
@@ -1,11 +1,16 @@
 error: implementation of `DistributedIteratorMulti` is not general enough
   --> $DIR/issue-55731.rs:48:5
    |
-LL |     multi(Map {
-   |     ^^^^^
+LL | / trait DistributedIteratorMulti<Source> {
+LL | |     type Item;
+LL | | }
+   | |_- trait `DistributedIteratorMulti` defined here
+...
+LL |       multi(Map {
+   |       ^^^^^ implementation of `DistributedIteratorMulti` is not general enough
    |
-   = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`
-   = note: but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
+   = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`...
+   = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-57362-1.stderr b/src/test/ui/issues/issue-57362-1.stderr
index 1d2ff76..c4000c8 100644
--- a/src/test/ui/issues/issue-57362-1.stderr
+++ b/src/test/ui/issues/issue-57362-1.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-57362-1.rs:20:7
    |
 LL |     a.f();
-   |       ^
+   |       ^ method not found in `fn(&u8)`
    |
    = note: a is a function, perhaps you wish to call it
    = help: items from traits can only be used if the trait is implemented and in scope
diff --git a/src/test/ui/issues/issue-60057.rs b/src/test/ui/issues/issue-60057.rs
index 3027d01..b52343a 100644
--- a/src/test/ui/issues/issue-60057.rs
+++ b/src/test/ui/issues/issue-60057.rs
@@ -15,3 +15,5 @@
         }
     }
 }
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-60057.stderr b/src/test/ui/issues/issue-60057.stderr
index 6b96720..4d915fc 100644
--- a/src/test/ui/issues/issue-60057.stderr
+++ b/src/test/ui/issues/issue-60057.stderr
@@ -10,11 +10,6 @@
 LL |             banana: banana
    |                     ^^^^^^ help: you might have meant to use the available field: `self.banana`
 
-error[E0601]: `main` function not found in crate `issue_60057`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-60057.rs`
+error: aborting due to 2 previous errors
 
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0425, E0601.
-For more information about an error, try `rustc --explain E0425`.
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/issues/issue-61711-once-caused-rustc-inf-loop.rs b/src/test/ui/issues/issue-61711-once-caused-rustc-inf-loop.rs
index 8fc09c8..de7d6a0 100644
--- a/src/test/ui/issues/issue-61711-once-caused-rustc-inf-loop.rs
+++ b/src/test/ui/issues/issue-61711-once-caused-rustc-inf-loop.rs
@@ -5,7 +5,7 @@
 // aux-build:xcrate-issue-61711-b.rs
 // compile-flags:--extern xcrate_issue_61711_b
 
-// run-pass
+// build-pass
 
 fn f<F: Fn(xcrate_issue_61711_b::Struct)>(_: F) { }
 fn main() { }
diff --git a/src/test/ui/issues/issue-64430.rs b/src/test/ui/issues/issue-64430.rs
new file mode 100644
index 0000000..0bc66e0
--- /dev/null
+++ b/src/test/ui/issues/issue-64430.rs
@@ -0,0 +1,14 @@
+// compile-flags:-C panic=abort
+
+#![no_std]
+pub struct Foo;
+
+fn main() {
+    Foo.bar()
+    //~^ ERROR E0599
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop{}
+}
diff --git a/src/test/ui/issues/issue-64430.stderr b/src/test/ui/issues/issue-64430.stderr
new file mode 100644
index 0000000..f1b2de8
--- /dev/null
+++ b/src/test/ui/issues/issue-64430.stderr
@@ -0,0 +1,12 @@
+error[E0599]: no method named `bar` found for type `Foo` in the current scope
+  --> $DIR/issue-64430.rs:7:9
+   |
+LL | pub struct Foo;
+   | --------------- method `bar` not found for this
+...
+LL |     Foo.bar()
+   |         ^^^ method not found in `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-6919.rs b/src/test/ui/issues/issue-6919.rs
index 11aed12..6f1e1f9 100644
--- a/src/test/ui/issues/issue-6919.rs
+++ b/src/test/ui/issues/issue-6919.rs
@@ -4,7 +4,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![crate_id="issue-6919"]
 extern crate issue6919_3;
 
 pub fn main() {
diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr
index dffbdb7..86cb2f0 100644
--- a/src/test/ui/json-short.stderr
+++ b/src/test/ui/json-short.stderr
@@ -11,7 +11,7 @@
 
 If you don't know the basics of Rust, you can go look to the Rust Book to get
 started: https://doc.rust-lang.org/book/
-"},"level":"error","spans":[],"children":[{"message":"consider adding a `main` function to `$DIR/json-short.rs`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"error[E0601]: `main` function not found in crate `json_short`
+"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":76,"byte_end":76,"line_start":2,"line_end":2,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:2:63: error[E0601]: `main` function not found in crate `json_short`
 "}
 {"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
 "}
diff --git a/src/test/ui/lifetime-before-type-params.rs b/src/test/ui/lifetime-before-type-params.rs
index 9b905d4..5a71d6e 100644
--- a/src/test/ui/lifetime-before-type-params.rs
+++ b/src/test/ui/lifetime-before-type-params.rs
@@ -7,3 +7,5 @@
 //~^ ERROR lifetime parameters must be declared prior to type parameters
 fn fourth<'a, T, 'b, U, 'c, V>() {}
 //~^ ERROR lifetime parameters must be declared prior to type parameters
+
+fn main() {}
diff --git a/src/test/ui/lifetime-before-type-params.stderr b/src/test/ui/lifetime-before-type-params.stderr
index ffc6784..76d7d0f 100644
--- a/src/test/ui/lifetime-before-type-params.stderr
+++ b/src/test/ui/lifetime-before-type-params.stderr
@@ -22,10 +22,5 @@
 LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
    |          --------^^-----^^---- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
 
-error[E0601]: `main` function not found in crate `lifetime_before_type_params`
-   |
-   = note: consider adding a `main` function to `$DIR/lifetime-before-type-params.rs`
+error: aborting due to 4 previous errors
 
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
index 779e2eb..2ed4d6d 100644
--- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
@@ -12,11 +12,11 @@
   --> $DIR/ex3-both-anon-regions-3.rs:2:5
    |
 LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
-   |                         -                    - let's call the lifetime of this reference `'1`
+   |                         -                    - let's call the lifetime of this reference `'3`
    |                         |
-   |                         let's call the lifetime of this reference `'2`
+   |                         let's call the lifetime of this reference `'4`
 LL |     z.push((x,y));
-   |     ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |     ^^^^^^^^^^^^^ argument requires that `'3` must outlive `'4`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lint/empty-lint-attributes.rs b/src/test/ui/lint/empty-lint-attributes.rs
index 1f0a953..9a0ec25 100644
--- a/src/test/ui/lint/empty-lint-attributes.rs
+++ b/src/test/ui/lint/empty-lint-attributes.rs
@@ -1,6 +1,6 @@
 #![feature(lint_reasons)]
 
-// run-pass
+// check-pass
 
 // Empty (and reason-only) lint attributes are legal—although we may want to
 // lint them in the future (Issue #55112).
diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.rs b/src/test/ui/lint/issue-54538-unused-parens-lint.rs
index 1d8cce5..7dcbdd0 100644
--- a/src/test/ui/lint/issue-54538-unused-parens-lint.rs
+++ b/src/test/ui/lint/issue-54538-unused-parens-lint.rs
@@ -1,4 +1,4 @@
-#![feature(box_patterns)]
+#![feature(box_patterns, stmt_expr_attributes)]
 
 #![feature(or_patterns)]
 //~^ WARN the feature `or_patterns` is incomplete
@@ -17,6 +17,10 @@
     let _ = |(a): u8| 0; //~ ERROR unnecessary parentheses around pattern
 }
 
+fn _no_lint_attr() {
+    let _x = #[allow(dead_code)] (1 + 2);
+}
+
 // Don't lint in these cases (#64106).
 fn or_patterns_no_lint() {
     match Box::new(0) {
diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr
index 7d5e286..675dd4f 100644
--- a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr
+++ b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr
@@ -49,109 +49,109 @@
    |              ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:41:12
+  --> $DIR/issue-54538-unused-parens-lint.rs:45:12
    |
 LL |     if let (0 | 1) = 0 {}
    |            ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:42:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:46:13
    |
 LL |     if let ((0 | 1),) = (0,) {}
    |             ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:43:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:47:13
    |
 LL |     if let [(0 | 1)] = [0] {}
    |             ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:44:16
+  --> $DIR/issue-54538-unused-parens-lint.rs:48:16
    |
 LL |     if let 0 | (1 | 2) = 0 {}
    |                ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:46:15
+  --> $DIR/issue-54538-unused-parens-lint.rs:50:15
    |
 LL |     if let TS((0 | 1)) = TS(0) {}
    |               ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:48:20
+  --> $DIR/issue-54538-unused-parens-lint.rs:52:20
    |
 LL |     if let NS { f: (0 | 1) } = (NS { f: 0 }) {}
    |                    ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:58:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:62:9
    |
 LL |         (_) => {}
    |         ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:59:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:63:9
    |
 LL |         (y) => {}
    |         ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:60:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:64:9
    |
 LL |         (ref r) => {}
    |         ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:61:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:65:9
    |
 LL |         (e @ 1...2) => {}
    |         ^^^^^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:67:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:71:9
    |
 LL |         (e @ &(1...2)) => {}
    |         ^^^^^^^^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:68:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:72:10
    |
 LL |         &(_) => {}
    |          ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:79:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:83:9
    |
 LL |         (_) => {}
    |         ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:80:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:84:9
    |
 LL |         (y) => {}
    |         ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:81:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:85:9
    |
 LL |         (ref r) => {}
    |         ^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:82:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:86:9
    |
 LL |         (e @ 1..=2) => {}
    |         ^^^^^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:88:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:92:9
    |
 LL |         (e @ &(1..=2)) => {}
    |         ^^^^^^^^^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:89:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:93:10
    |
 LL |         &(_) => {}
    |          ^^^ help: remove these parentheses
diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs
index e1f4b0b..3898e67 100644
--- a/src/test/ui/lint/lint-ctypes-enum.rs
+++ b/src/test/ui/lint/lint-ctypes-enum.rs
@@ -36,36 +36,37 @@
 
 extern {
    fn zf(x: Z);
-   fn uf(x: U); //~ ERROR enum has no representation hint
-   fn bf(x: B); //~ ERROR enum has no representation hint
-   fn tf(x: T); //~ ERROR enum has no representation hint
+   fn uf(x: U); //~ ERROR `extern` block uses type `U`
+   fn bf(x: B); //~ ERROR `extern` block uses type `B`
+   fn tf(x: T); //~ ERROR `extern` block uses type `T`
    fn repr_c(x: ReprC);
    fn repr_u8(x: U8);
    fn repr_isize(x: Isize);
    fn option_ref(x: Option<&'static u8>);
    fn option_fn(x: Option<extern "C" fn()>);
    fn nonnull(x: Option<std::ptr::NonNull<u8>>);
-   fn unique(x: Option<std::ptr::Unique<u8>>); //~ ERROR enum has no representation hint
+   fn unique(x: Option<std::ptr::Unique<u8>>);
+   //~^ ERROR `extern` block uses type `std::option::Option<std::ptr::Unique<u8>>`
    fn nonzero_u8(x: Option<num::NonZeroU8>);
    fn nonzero_u16(x: Option<num::NonZeroU16>);
    fn nonzero_u32(x: Option<num::NonZeroU32>);
    fn nonzero_u64(x: Option<num::NonZeroU64>);
    fn nonzero_u128(x: Option<num::NonZeroU128>);
-   //~^ ERROR 128-bit integers don't currently have a known stable ABI
+   //~^ ERROR `extern` block uses type `u128`
    fn nonzero_usize(x: Option<num::NonZeroUsize>);
    fn nonzero_i8(x: Option<num::NonZeroI8>);
    fn nonzero_i16(x: Option<num::NonZeroI16>);
    fn nonzero_i32(x: Option<num::NonZeroI32>);
    fn nonzero_i64(x: Option<num::NonZeroI64>);
    fn nonzero_i128(x: Option<num::NonZeroI128>);
-   //~^ ERROR 128-bit integers don't currently have a known stable ABI
+   //~^ ERROR `extern` block uses type `i128`
    fn nonzero_isize(x: Option<num::NonZeroIsize>);
    fn transparent_struct(x: Option<TransparentStruct<num::NonZeroU8>>);
    fn transparent_enum(x: Option<TransparentEnum<num::NonZeroU8>>);
    fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>);
-   //~^ ERROR enum has no representation hint
-   fn repr_rust(x: Option<Rust<num::NonZeroU8>>); //~ ERROR enum has no representation hint
-   fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR enum has no representation hint
+   //~^ ERROR `extern` block uses type
+   fn repr_rust(x: Option<Rust<num::NonZeroU8>>); //~ ERROR `extern` block uses type
+   fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR `extern` block uses type
 }
 
-pub fn main() { }
+pub fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr
index 20e4386..81939e6 100644
--- a/src/test/ui/lint/lint-ctypes-enum.stderr
+++ b/src/test/ui/lint/lint-ctypes-enum.stderr
@@ -1,8 +1,8 @@
-error: `extern` block uses type `U` which is not FFI-safe: enum has no representation hint
+error: `extern` block uses type `U`, which is not FFI-safe
   --> $DIR/lint-ctypes-enum.rs:39:13
    |
 LL |    fn uf(x: U);
-   |             ^
+   |             ^ not FFI-safe
    |
 note: lint level defined here
   --> $DIR/lint-ctypes-enum.rs:3:9
@@ -10,81 +10,92 @@
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
 note: type defined here
   --> $DIR/lint-ctypes-enum.rs:9:1
    |
 LL | enum U { A }
    | ^^^^^^^^^^^^
 
-error: `extern` block uses type `B` which is not FFI-safe: enum has no representation hint
+error: `extern` block uses type `B`, which is not FFI-safe
   --> $DIR/lint-ctypes-enum.rs:40:13
    |
 LL |    fn bf(x: B);
-   |             ^
+   |             ^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
 note: type defined here
   --> $DIR/lint-ctypes-enum.rs:10:1
    |
 LL | enum B { C, D }
    | ^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `T` which is not FFI-safe: enum has no representation hint
+error: `extern` block uses type `T`, which is not FFI-safe
   --> $DIR/lint-ctypes-enum.rs:41:13
    |
 LL |    fn tf(x: T);
-   |             ^
+   |             ^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
 note: type defined here
   --> $DIR/lint-ctypes-enum.rs:11:1
    |
 LL | enum T { E, F, G }
    | ^^^^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `std::option::Option<std::ptr::Unique<u8>>` which is not FFI-safe: enum has no representation hint
+error: `extern` block uses type `std::option::Option<std::ptr::Unique<u8>>`, which is not FFI-safe
   --> $DIR/lint-ctypes-enum.rs:48:17
    |
 LL |    fn unique(x: Option<std::ptr::Unique<u8>>);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
 
-error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
-  --> $DIR/lint-ctypes-enum.rs:53:23
+error: `extern` block uses type `u128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:54:23
    |
 LL |    fn nonzero_u128(x: Option<num::NonZeroU128>);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
-  --> $DIR/lint-ctypes-enum.rs:60:23
+error: `extern` block uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:61:23
    |
 LL |    fn nonzero_i128(x: Option<num::NonZeroI128>);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `std::option::Option<TransparentUnion<std::num::NonZeroU8>>` which is not FFI-safe: enum has no representation hint
-  --> $DIR/lint-ctypes-enum.rs:65:28
+error: `extern` block uses type `std::option::Option<TransparentUnion<std::num::NonZeroU8>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:66:28
    |
 LL |    fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>);
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
 
-error: `extern` block uses type `std::option::Option<Rust<std::num::NonZeroU8>>` which is not FFI-safe: enum has no representation hint
-  --> $DIR/lint-ctypes-enum.rs:67:20
-   |
-LL |    fn repr_rust(x: Option<Rust<num::NonZeroU8>>);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
-
-error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>` which is not FFI-safe: enum has no representation hint
+error: `extern` block uses type `std::option::Option<Rust<std::num::NonZeroU8>>`, which is not FFI-safe
   --> $DIR/lint-ctypes-enum.rs:68:20
    |
-LL |    fn no_result(x: Result<(), num::NonZeroI32>);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |    fn repr_rust(x: Option<Rust<num::NonZeroU8>>);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:69:20
+   |
+LL |    fn no_result(x: Result<(), num::NonZeroI32>);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs
index a3d9b6f..e20503a 100644
--- a/src/test/ui/lint/lint-ctypes.rs
+++ b/src/test/ui/lint/lint-ctypes.rs
@@ -1,7 +1,7 @@
-#![deny(improper_ctypes)]
 #![feature(rustc_private)]
 
 #![allow(private_in_public)]
+#![deny(improper_ctypes)]
 
 extern crate libc;
 
@@ -54,12 +54,13 @@
     pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn std::clone::Clone`
     pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
     pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
-    pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields
-    pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData
+    pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`
+    pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
+    //~^ ERROR uses type `ZeroSizeWithPhantomData`
     pub fn zero_size_phantom_toplevel()
-        -> ::std::marker::PhantomData<bool>; //~ ERROR: composed only of PhantomData
-    pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific
-    pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific
+        -> ::std::marker::PhantomData<bool>; //~ ERROR uses type `std::marker::PhantomData<bool>`
+    pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()`
+    pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()`
     pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box<u32>`
     pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128`
     pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr
index c78463b..e533a76 100644
--- a/src/test/ui/lint/lint-ctypes.stderr
+++ b/src/test/ui/lint/lint-ctypes.stderr
@@ -1,170 +1,201 @@
-error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `Foo`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:46:28
    |
 LL |     pub fn ptr_type1(size: *const Foo);
-   |                            ^^^^^^^^^^
+   |                            ^^^^^^^^^^ not FFI-safe
    |
 note: lint level defined here
-  --> $DIR/lint-ctypes.rs:1:9
+  --> $DIR/lint-ctypes.rs:4:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/lint-ctypes.rs:24:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `Foo`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:47:28
    |
 LL |     pub fn ptr_type2(size: *const Foo);
-   |                            ^^^^^^^^^^
+   |                            ^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 note: type defined here
   --> $DIR/lint-ctypes.rs:24:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent
+error: `extern` block uses type `[u32]`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:48:26
    |
 LL |     pub fn slice_type(p: &[u32]);
-   |                          ^^^^^^
+   |                          ^^^^^^ not FFI-safe
    |
    = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
 
-error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent
+error: `extern` block uses type `str`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:49:24
    |
 LL |     pub fn str_type(p: &str);
-   |                        ^^^^
+   |                        ^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
 
-error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
+error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:50:24
    |
 LL |     pub fn box_type(p: Box<u32>);
-   |                        ^^^^^^^^
+   |                        ^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 
-error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent
+error: `extern` block uses type `char`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:51:25
    |
 LL |     pub fn char_type(p: char);
-   |                         ^^^^
+   |                         ^^^^ not FFI-safe
    |
    = help: consider using `u32` or `libc::wchar_t` instead
+   = note: the `char` type has no C equivalent
 
-error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
+error: `extern` block uses type `i128`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:52:25
    |
 LL |     pub fn i128_type(p: i128);
-   |                         ^^^^
+   |                         ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
+error: `extern` block uses type `u128`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:53:25
    |
 LL |     pub fn u128_type(p: u128);
-   |                         ^^^^
+   |                         ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `dyn std::clone::Clone` which is not FFI-safe: trait objects have no C equivalent
+error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:54:26
    |
 LL |     pub fn trait_type(p: &dyn Clone);
-   |                          ^^^^^^^^^^
+   |                          ^^^^^^^^^^ not FFI-safe
+   |
+   = note: trait objects have no C equivalent
 
-error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout
+error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:55:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
-   |                          ^^^^^^^^^^
+   |                          ^^^^^^^^^^ not FFI-safe
    |
    = help: consider using a struct instead
+   = note: tuples have unspecified layout
 
-error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout
+error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:56:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
-   |                           ^^^^^^^
+   |                           ^^^^^^^ not FFI-safe
    |
    = help: consider using a struct instead
+   = note: tuples have unspecified layout
 
-error: `extern` block uses type `ZeroSize` which is not FFI-safe: this struct has no fields
+error: `extern` block uses type `ZeroSize`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:57:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
-   |                         ^^^^^^^^
+   |                         ^^^^^^^^ not FFI-safe
    |
    = help: consider adding a member to this struct
+   = note: this struct has no fields
 note: type defined here
   --> $DIR/lint-ctypes.rs:20:1
    |
 LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `ZeroSizeWithPhantomData` which is not FFI-safe: composed only of PhantomData
+error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:58:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
+note: type defined here
+  --> $DIR/lint-ctypes.rs:43:1
+   |
+LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `std::marker::PhantomData<bool>` which is not FFI-safe: composed only of PhantomData
-  --> $DIR/lint-ctypes.rs:60:12
+error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:61:12
    |
 LL |         -> ::std::marker::PhantomData<bool>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
 
-error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention
-  --> $DIR/lint-ctypes.rs:61:23
+error: `extern` block uses type `fn()`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:62:23
    |
 LL |     pub fn fn_type(p: RustFn);
-   |                       ^^^^^^
+   |                       ^^^^^^ not FFI-safe
    |
    = help: consider using an `extern fn(...) -> ...` function pointer instead
+   = note: this function pointer has Rust-specific calling convention
 
-error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention
-  --> $DIR/lint-ctypes.rs:62:24
+error: `extern` block uses type `fn()`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:63:24
    |
 LL |     pub fn fn_type2(p: fn());
-   |                        ^^^^
+   |                        ^^^^ not FFI-safe
    |
    = help: consider using an `extern fn(...) -> ...` function pointer instead
+   = note: this function pointer has Rust-specific calling convention
 
-error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
-  --> $DIR/lint-ctypes.rs:63:28
+error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:64:28
    |
 LL |     pub fn fn_contained(p: RustBadRet);
-   |                            ^^^^^^^^^^
+   |                            ^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 
-error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
-  --> $DIR/lint-ctypes.rs:64:32
+error: `extern` block uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:65:32
    |
 LL |     pub fn transparent_i128(p: TransparentI128);
-   |                                ^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent
-  --> $DIR/lint-ctypes.rs:65:31
+error: `extern` block uses type `str`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:66:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
-   |                               ^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
 
-error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
-  --> $DIR/lint-ctypes.rs:66:30
+error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:67:30
    |
 LL |     pub fn transparent_fn(p: TransparentBadFn);
-   |                              ^^^^^^^^^^^^^^^^
+   |                              ^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 
 error: aborting due to 20 previous errors
 
diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
new file mode 100644
index 0000000..25d5f8e
--- /dev/null
+++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
@@ -0,0 +1,16 @@
+#![feature(type_alias_impl_trait)]
+
+#![deny(improper_ctypes)]
+
+type A = impl Fn();
+
+pub fn ret_closure() -> A {
+    || {}
+}
+
+extern "C" {
+    pub fn a(_: A);
+    //~^ ERROR `extern` block uses type `A`, which is not FFI-safe
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
new file mode 100644
index 0000000..136d564
--- /dev/null
+++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
@@ -0,0 +1,15 @@
+error: `extern` block uses type `A`, which is not FFI-safe
+  --> $DIR/opaque-ty-ffi-unsafe.rs:12:17
+   |
+LL |     pub fn a(_: A);
+   |                 ^ not FFI-safe
+   |
+note: lint level defined here
+  --> $DIR/opaque-ty-ffi-unsafe.rs:3:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
index 015e05e..96054de 100644
--- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
+++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
@@ -2,7 +2,7 @@
   --> $DIR/macro-backtrace-invalid-internals.rs:5:13
    |
 LL |           1.fake()
-   |             ^^^^
+   |             ^^^^ method not found in `{integer}`
 ...
 LL |     fake_method_stmt!();
    |     -------------------- in this macro invocation
@@ -42,7 +42,7 @@
   --> $DIR/macro-backtrace-invalid-internals.rs:23:13
    |
 LL |           1.fake()
-   |             ^^^^
+   |             ^^^^ method not found in `{integer}`
 ...
 LL |     let _ = fake_method_expr!();
    |             ------------------- in this macro invocation
diff --git a/src/test/ui/macros/macro-expansion-tests.stderr b/src/test/ui/macros/macro-expansion-tests.stderr
index 4ad9ade..8b3f7ca 100644
--- a/src/test/ui/macros/macro-expansion-tests.stderr
+++ b/src/test/ui/macros/macro-expansion-tests.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/macro-expansion-tests.rs:7:21
    |
 LL |     fn g() -> i32 { m!() }
@@ -6,7 +6,7 @@
    |
    = help: have you added the `#[macro_use]` on the module/import?
 
-error: cannot find macro `m!` in this scope
+error: cannot find macro `m` in this scope
   --> $DIR/macro-expansion-tests.rs:15:21
    |
 LL |     fn g() -> i32 { m!() }
diff --git a/src/test/ui/macros/macro-name-typo.stderr b/src/test/ui/macros/macro-name-typo.stderr
index 967f4f3..ce2e198 100644
--- a/src/test/ui/macros/macro-name-typo.stderr
+++ b/src/test/ui/macros/macro-name-typo.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `printlx!` in this scope
+error: cannot find macro `printlx` in this scope
   --> $DIR/macro-name-typo.rs:2:5
    |
 LL |     printlx!("oh noes!");
diff --git a/src/test/ui/macros/macro-path-prelude-fail-3.rs b/src/test/ui/macros/macro-path-prelude-fail-3.rs
index 597053d..68eb350 100644
--- a/src/test/ui/macros/macro-path-prelude-fail-3.rs
+++ b/src/test/ui/macros/macro-path-prelude-fail-3.rs
@@ -1,3 +1,3 @@
 fn main() {
-    inline!(); //~ ERROR cannot find macro `inline!` in this scope
+    inline!(); //~ ERROR cannot find macro `inline` in this scope
 }
diff --git a/src/test/ui/macros/macro-path-prelude-fail-3.stderr b/src/test/ui/macros/macro-path-prelude-fail-3.stderr
index 96b8a24..ec00760 100644
--- a/src/test/ui/macros/macro-path-prelude-fail-3.stderr
+++ b/src/test/ui/macros/macro-path-prelude-fail-3.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `inline!` in this scope
+error: cannot find macro `inline` in this scope
   --> $DIR/macro-path-prelude-fail-3.rs:2:5
    |
 LL |     inline!();
diff --git a/src/test/ui/macros/macro-reexport-removed.rs b/src/test/ui/macros/macro-reexport-removed.rs
index b69a1fa..874c94d 100644
--- a/src/test/ui/macros/macro-reexport-removed.rs
+++ b/src/test/ui/macros/macro-reexport-removed.rs
@@ -2,7 +2,7 @@
 
 #![feature(macro_reexport)] //~ ERROR feature has been removed
 
-#[macro_reexport(macro_one)] //~ ERROR cannot find attribute macro `macro_reexport` in this scope
+#[macro_reexport(macro_one)] //~ ERROR cannot find attribute `macro_reexport` in this scope
 extern crate two_macros;
 
 fn main() {}
diff --git a/src/test/ui/macros/macro-reexport-removed.stderr b/src/test/ui/macros/macro-reexport-removed.stderr
index 25778fb..4bec708 100644
--- a/src/test/ui/macros/macro-reexport-removed.stderr
+++ b/src/test/ui/macros/macro-reexport-removed.stderr
@@ -10,7 +10,7 @@
 LL | #![feature(macro_reexport)]
    |            ^^^^^^^^^^^^^^
 
-error: cannot find attribute macro `macro_reexport` in this scope
+error: cannot find attribute `macro_reexport` in this scope
   --> $DIR/macro-reexport-removed.rs:5:3
    |
 LL | #[macro_reexport(macro_one)]
diff --git a/src/test/ui/macros/macro-use-wrong-name.stderr b/src/test/ui/macros/macro-use-wrong-name.stderr
index 28f727d..8b4e90a 100644
--- a/src/test/ui/macros/macro-use-wrong-name.stderr
+++ b/src/test/ui/macros/macro-use-wrong-name.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `macro_two!` in this scope
+error: cannot find macro `macro_two` in this scope
   --> $DIR/macro-use-wrong-name.rs:7:5
    |
 LL |     macro_two!();
diff --git a/src/test/ui/macros/macro_undefined.stderr b/src/test/ui/macros/macro_undefined.stderr
index 9239b2a..01c8ebe 100644
--- a/src/test/ui/macros/macro_undefined.stderr
+++ b/src/test/ui/macros/macro_undefined.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `k!` in this scope
+error: cannot find macro `k` in this scope
   --> $DIR/macro_undefined.rs:11:5
    |
 LL |     k!();
diff --git a/src/test/ui/main-wrong-location.rs b/src/test/ui/main-wrong-location.rs
index d7ed512..f75d088 100644
--- a/src/test/ui/main-wrong-location.rs
+++ b/src/test/ui/main-wrong-location.rs
@@ -1,4 +1,5 @@
 mod m {
+//~^ ERROR `main` function not found
     // An inferred main entry point (that doesn't use #[main])
     // must appear at the top of the crate
     fn main() { }
diff --git a/src/test/ui/main-wrong-location.stderr b/src/test/ui/main-wrong-location.stderr
index b30931f..e301c2f 100644
--- a/src/test/ui/main-wrong-location.stderr
+++ b/src/test/ui/main-wrong-location.stderr
@@ -1,11 +1,21 @@
 error[E0601]: `main` function not found in crate `main_wrong_location`
+  --> $DIR/main-wrong-location.rs:1:1
    |
-   = note: the main function must be defined at the crate level but you have one or more functions named 'main' that are not defined at the crate level. Either move the definition or attach the `#[main]` attribute to override this behavior.
-note: here is a function named 'main'
-  --> $DIR/main-wrong-location.rs:4:5
+LL | / mod m {
+LL | |
+LL | |     // An inferred main entry point (that doesn't use #[main])
+LL | |     // must appear at the top of the crate
+LL | |     fn main() { }
+LL | | }
+   | |_^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`)
+   |
+note: here is a function named `main`
+  --> $DIR/main-wrong-location.rs:5:5
    |
 LL |     fn main() { }
    |     ^^^^^^^^^^^^^
+   = note: you have one or more functions named `main` not defined at the crate level
+   = help: either move the `main` function definitions or attach the `#[main]` attribute to one of them
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/match/match-ref-mut-stability.rs b/src/test/ui/match/match-ref-mut-stability.rs
index 49e0dfa..5212036 100644
--- a/src/test/ui/match/match-ref-mut-stability.rs
+++ b/src/test/ui/match/match-ref-mut-stability.rs
@@ -3,8 +3,6 @@
 
 // run-pass
 
-#![feature(bind_by_move_pattern_guards)]
-
 // Test that z always point to the same temporary.
 fn referent_stability() {
     let p;
diff --git a/src/test/ui/match/non-exhaustive-defined-here.rs b/src/test/ui/match/non-exhaustive-defined-here.rs
new file mode 100644
index 0000000..6f009ac
--- /dev/null
+++ b/src/test/ui/match/non-exhaustive-defined-here.rs
@@ -0,0 +1,72 @@
+// Test the "defined here" and "not covered" diagnostic hints.
+// We also make sure that references are peeled off from the scrutinee type
+// so that the diagnostics work better with default binding modes.
+
+#[derive(Clone)]
+enum E {
+//~^ `E` defined here
+//~| `E` defined here
+//~| `E` defined here
+//~| `E` defined here
+//~| `E` defined here
+//~| `E` defined here
+    A,
+    B,
+    //~^ not covered
+    //~| not covered
+    //~| not covered
+    //~| not covered
+    //~| not covered
+    //~| not covered
+    C
+    //~^ not covered
+    //~| not covered
+    //~| not covered
+    //~| not covered
+    //~| not covered
+    //~| not covered
+}
+
+fn by_val(e: E) {
+    let e1 = e.clone();
+    match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
+        E::A => {}
+    }
+
+    let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
+}
+
+fn by_ref_once(e: &E) {
+    match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
+        E::A => {}
+    }
+
+    let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
+}
+
+fn by_ref_thrice(e: & &mut &E) {
+    match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
+        E::A => {}
+    }
+
+    let E::A = e;
+    //~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
+}
+
+enum Opt {
+//~^ `Opt` defined here
+//~| `Opt` defined here
+    Some(u8),
+    None,
+    //~^ not covered
+}
+
+fn ref_pat(e: Opt) {
+    match e {//~ ERROR non-exhaustive patterns: `None` not covered
+        Opt::Some(ref _x) => {}
+    }
+
+    let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
+}
+
+fn main() {}
diff --git a/src/test/ui/match/non-exhaustive-defined-here.stderr b/src/test/ui/match/non-exhaustive-defined-here.stderr
new file mode 100644
index 0000000..25b8bbd
--- /dev/null
+++ b/src/test/ui/match/non-exhaustive-defined-here.stderr
@@ -0,0 +1,170 @@
+error[E0004]: non-exhaustive patterns: `B` and `C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:32:11
+   |
+LL | / enum E {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     B,
+   | |     - not covered
+...  |
+LL | |     C
+   | |     - not covered
+...  |
+LL | |
+LL | | }
+   | |_- `E` defined here
+...
+LL |       match e1 {
+   |             ^^ patterns `B` and `C` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0005]: refutable pattern in local binding: `B` and `C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:36:9
+   |
+LL | / enum E {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     B,
+   | |     - not covered
+...  |
+LL | |     C
+   | |     - not covered
+...  |
+LL | |
+LL | | }
+   | |_- `E` defined here
+...
+LL |       let E::A = e;
+   |           ^^^^ patterns `B` and `C` not covered
+
+error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:40:11
+   |
+LL | / enum E {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     B,
+   | |     - not covered
+...  |
+LL | |     C
+   | |     - not covered
+...  |
+LL | |
+LL | | }
+   | |_- `E` defined here
+...
+LL |       match e {
+   |             ^ patterns `&B` and `&C` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:44:9
+   |
+LL | / enum E {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     B,
+   | |     - not covered
+...  |
+LL | |     C
+   | |     - not covered
+...  |
+LL | |
+LL | | }
+   | |_- `E` defined here
+...
+LL |       let E::A = e;
+   |           ^^^^ patterns `&B` and `&C` not covered
+
+error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:48:11
+   |
+LL | / enum E {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     B,
+   | |     - not covered
+...  |
+LL | |     C
+   | |     - not covered
+...  |
+LL | |
+LL | | }
+   | |_- `E` defined here
+...
+LL |       match e {
+   |             ^ patterns `&&mut &B` and `&&mut &C` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:52:9
+   |
+LL | / enum E {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     B,
+   | |     - not covered
+...  |
+LL | |     C
+   | |     - not covered
+...  |
+LL | |
+LL | | }
+   | |_- `E` defined here
+...
+LL |       let E::A = e;
+   |           ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
+
+error[E0004]: non-exhaustive patterns: `None` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:65:11
+   |
+LL | / enum Opt {
+LL | |
+LL | |
+LL | |     Some(u8),
+LL | |     None,
+   | |     ---- not covered
+LL | |
+LL | | }
+   | |_- `Opt` defined here
+...
+LL |       match e {
+   |             ^ pattern `None` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0005]: refutable pattern in local binding: `None` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:69:9
+   |
+LL | / enum Opt {
+LL | |
+LL | |
+LL | |     Some(u8),
+LL | |     None,
+   | |     ---- not covered
+LL | |
+LL | | }
+   | |_- `Opt` defined here
+...
+LL |       let Opt::Some(ref _x) = e;
+   |           ^^^^^^^^^^^^^^^^^ pattern `None` not covered
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0004, E0005.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr
index b8ae4c3..94c27b7 100644
--- a/src/test/ui/methods/method-call-err-msg.stderr
+++ b/src/test/ui/methods/method-call-err-msg.stderr
@@ -32,7 +32,7 @@
    | --------------- method `take` not found for this
 ...
 LL |      .take()
-   |       ^^^^
+   |       ^^^^ method not found in `Foo`
    |
    = note: the method `take` exists but the following trait bounds were not satisfied:
            `&mut Foo : std::iter::Iterator`
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index 3f87ef7..89c7b09 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-36053-2.rs:7:55
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                                       ^^^^^
+   |                                                       ^^^^^ method not found in `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>`
    |
    = note: the method `count` exists but the following trait bounds were not satisfied:
            `&mut std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]> : std::iter::Iterator`
diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr
index 9721dc8..865092e 100644
--- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr
+++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr
@@ -2,7 +2,7 @@
   --> $DIR/method-help-unsatisfied-bound.rs:5:7
    |
 LL |     a.unwrap();
-   |       ^^^^^^
+   |       ^^^^^^ method not found in `std::result::Result<(), Foo>`
    |
    = note: the method `unwrap` exists but the following trait bounds were not satisfied:
            `Foo : std::fmt::Debug`
diff --git a/src/test/ui/missing/missing-macro-use.rs b/src/test/ui/missing/missing-macro-use.rs
index dff4c94..d494c44 100644
--- a/src/test/ui/missing/missing-macro-use.rs
+++ b/src/test/ui/missing/missing-macro-use.rs
@@ -4,5 +4,5 @@
 
 pub fn main() {
     macro_two!();
-    //~^ ERROR cannot find macro `macro_two!` in this scope
+    //~^ ERROR cannot find macro `macro_two` in this scope
 }
diff --git a/src/test/ui/missing/missing-macro-use.stderr b/src/test/ui/missing/missing-macro-use.stderr
index 01a7beb..711e249 100644
--- a/src/test/ui/missing/missing-macro-use.stderr
+++ b/src/test/ui/missing/missing-macro-use.stderr
@@ -1,4 +1,4 @@
-error: cannot find macro `macro_two!` in this scope
+error: cannot find macro `macro_two` in this scope
   --> $DIR/missing-macro-use.rs:6:5
    |
 LL |     macro_two!();
diff --git a/src/test/ui/missing/missing-main.stderr b/src/test/ui/missing/missing-main.stderr
index 34b03ad..6a35f51 100644
--- a/src/test/ui/missing/missing-main.stderr
+++ b/src/test/ui/missing/missing-main.stderr
@@ -1,6 +1,8 @@
 error[E0601]: `main` function not found in crate `missing_main`
+  --> $DIR/missing-main.rs:2:1
    |
-   = note: consider adding a `main` function to `$DIR/missing-main.rs`
+LL | fn mian() { }
+   | ^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/missing-main.rs`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-55288.rs b/src/test/ui/nll/issue-55288.rs
index c7b6ac5..aab2dc2 100644
--- a/src/test/ui/nll/issue-55288.rs
+++ b/src/test/ui/nll/issue-55288.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 struct Slice(&'static [&'static [u8]]);
 
diff --git a/src/test/ui/nll/issue-57960.rs b/src/test/ui/nll/issue-57960.rs
index 1399694..32e4518 100644
--- a/src/test/ui/nll/issue-57960.rs
+++ b/src/test/ui/nll/issue-57960.rs
@@ -30,7 +30,6 @@
         OneDigit::FIRST..=OneDigit::LAST => 1,
         TwoDigits::FIRST..=TwoDigits::LAST => 2,
         ThreeDigits::FIRST..=ThreeDigits::LAST => 3,
-        _ => unreachable!(),
     }
 }
 
diff --git a/src/test/ui/nll/match-cfg-fake-edges.rs b/src/test/ui/nll/match-cfg-fake-edges.rs
index 5fc9966..2e6d675 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.rs
+++ b/src/test/ui/nll/match-cfg-fake-edges.rs
@@ -1,8 +1,6 @@
 // Test that we have enough false edges to avoid exposing the exact matching
 // algorithm in borrow checking.
 
-#![feature(bind_by_move_pattern_guards)]
-
 fn guard_always_precedes_arm(y: i32) {
     let mut x;
     // x should always be initialized, as the only way to reach the arm is
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index 3d9037b..06fe564 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -1,11 +1,11 @@
 error[E0381]: use of possibly-uninitialized variable: `x`
-  --> $DIR/match-cfg-fake-edges.rs:23:13
+  --> $DIR/match-cfg-fake-edges.rs:21:13
    |
 LL |             x;
    |             ^ use of possibly-uninitialized `x`
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:37:13
+  --> $DIR/match-cfg-fake-edges.rs:35:13
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/match-guards-partially-borrow.rs b/src/test/ui/nll/match-guards-partially-borrow.rs
index 601c46f..81ae19e 100644
--- a/src/test/ui/nll/match-guards-partially-borrow.rs
+++ b/src/test/ui/nll/match-guards-partially-borrow.rs
@@ -5,8 +5,6 @@
 // Test that we don't allow mutating the value being matched on in a way that
 // changes which patterns it matches, until we have chosen an arm.
 
-#![feature(bind_by_move_pattern_guards)]
-
 fn ok_mutation_in_guard(mut q: i32) {
     match q {
         // OK, mutation doesn't change which patterns g matches
diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr
index b2951fd..48e3a7c 100644
--- a/src/test/ui/nll/match-guards-partially-borrow.stderr
+++ b/src/test/ui/nll/match-guards-partially-borrow.stderr
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `q` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:57:13
+  --> $DIR/match-guards-partially-borrow.rs:55:13
    |
 LL |     match q {
    |           - value is immutable in match guard
@@ -8,7 +8,7 @@
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `r` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:69:13
+  --> $DIR/match-guards-partially-borrow.rs:67:13
    |
 LL |     match r {
    |           - value is immutable in match guard
@@ -17,7 +17,7 @@
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `t` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:93:13
+  --> $DIR/match-guards-partially-borrow.rs:91:13
    |
 LL |     match t {
    |           - value is immutable in match guard
@@ -26,7 +26,7 @@
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x.0` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:107:22
+  --> $DIR/match-guards-partially-borrow.rs:105:22
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -35,7 +35,7 @@
    |                      ^^^^^^^^^ cannot mutably borrow
 
 error[E0506]: cannot assign to `t` because it is borrowed
-  --> $DIR/match-guards-partially-borrow.rs:119:13
+  --> $DIR/match-guards-partially-borrow.rs:117:13
    |
 LL |         s if {
    |         - borrow of `t` occurs here
@@ -46,7 +46,7 @@
    |         - borrow later used here
 
 error[E0510]: cannot assign `y` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:130:13
+  --> $DIR/match-guards-partially-borrow.rs:128:13
    |
 LL |     match *y {
    |           -- value is immutable in match guard
@@ -55,7 +55,7 @@
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `z` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:141:13
+  --> $DIR/match-guards-partially-borrow.rs:139:13
    |
 LL |     match z {
    |           - value is immutable in match guard
@@ -64,7 +64,7 @@
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `a` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:153:13
+  --> $DIR/match-guards-partially-borrow.rs:151:13
    |
 LL |     match a {
    |           - value is immutable in match guard
@@ -73,7 +73,7 @@
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `b` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:164:13
+  --> $DIR/match-guards-partially-borrow.rs:162:13
    |
 LL |     match b {
    |           - value is immutable in match guard
diff --git a/src/test/ui/nll/normalization-bounds.rs b/src/test/ui/nll/normalization-bounds.rs
index 5d2825e..bb6d981 100644
--- a/src/test/ui/nll/normalization-bounds.rs
+++ b/src/test/ui/nll/normalization-bounds.rs
@@ -1,6 +1,6 @@
 // Check that lifetime bounds get checked the right way around with NLL enabled.
 
-//run-pass
+// check-pass
 
 trait Visitor<'d> {
     type Value;
diff --git a/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs b/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
index 6d5bdfa..3b06b0d 100644
--- a/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
+++ b/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
@@ -1,11 +1,11 @@
 // Check that mutable promoted length zero arrays don't check for conflicting
 // access
 
-// run-pass
+// check-pass
 
 pub fn main() {
     let mut x: Vec<&[i32; 0]> = Vec::new();
-    for i in 0..10 {
+    for _ in 0..10 {
         x.push(&[]);
     }
 }
diff --git a/src/test/ui/nll/user-annotations/issue-55219.rs b/src/test/ui/nll/user-annotations/issue-55219.rs
index 4d18e96..1474136 100644
--- a/src/test/ui/nll/user-annotations/issue-55219.rs
+++ b/src/test/ui/nll/user-annotations/issue-55219.rs
@@ -3,7 +3,7 @@
 // The `Self::HASH_LEN` here expands to a "self-type" where `T` is not
 // known. This unbound inference variable was causing an ICE.
 //
-// run-pass
+// check-pass
 
 pub struct Foo<T>(T);
 
diff --git a/src/test/ui/nll/user-annotations/normalize-self-ty.rs b/src/test/ui/nll/user-annotations/normalize-self-ty.rs
index a06229a..df905c8 100644
--- a/src/test/ui/nll/user-annotations/normalize-self-ty.rs
+++ b/src/test/ui/nll/user-annotations/normalize-self-ty.rs
@@ -2,7 +2,7 @@
 // the inherent impl requires normalization to be equal to the
 // user-provided type.
 //
-// run-pass
+// check-pass
 
 trait Mirror {
     type Me;
@@ -15,7 +15,7 @@
 struct Foo<A, B>(A, B);
 
 impl<A> Foo<A, <A as Mirror>::Me> {
-    fn m(b: A) { }
+    fn m(_: A) { }
 }
 
 fn main() {
diff --git a/src/test/ui/non-copyable-void.stderr b/src/test/ui/non-copyable-void.stderr
index 4041e19..b05c29c 100644
--- a/src/test/ui/non-copyable-void.stderr
+++ b/src/test/ui/non-copyable-void.stderr
@@ -2,7 +2,7 @@
   --> $DIR/non-copyable-void.rs:11:23
    |
 LL |         let _z = (*y).clone();
-   |                       ^^^^^
+   |                       ^^^^^ method not found in `libc::c_void`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr
index eb47a33..c1c5021 100644
--- a/src/test/ui/noncopyable-class.stderr
+++ b/src/test/ui/noncopyable-class.stderr
@@ -5,7 +5,7 @@
    | ---------- method `clone` not found for this
 ...
 LL |     let _y = x.clone();
-   |                ^^^^^
+   |                ^^^^^ method not found in `Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
diff --git a/src/test/ui/object-pointer-types.stderr b/src/test/ui/object-pointer-types.stderr
index 0c7e4e9..2df628e 100644
--- a/src/test/ui/object-pointer-types.stderr
+++ b/src/test/ui/object-pointer-types.stderr
@@ -2,7 +2,7 @@
   --> $DIR/object-pointer-types.rs:11:7
    |
 LL |     x.owned();
-   |       ^^^^^
+   |       ^^^^^ method not found in `&dyn Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `owned`, perhaps you need to implement it:
@@ -12,7 +12,7 @@
   --> $DIR/object-pointer-types.rs:17:7
    |
 LL |     x.owned();
-   |       ^^^^^
+   |       ^^^^^ method not found in `&mut dyn Foo`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `owned`, perhaps you need to implement it:
@@ -22,7 +22,7 @@
   --> $DIR/object-pointer-types.rs:23:7
    |
 LL |     x.managed();
-   |       ^^^^^^^
+   |       ^^^^^^^ method not found in `std::boxed::Box<(dyn Foo + 'static)>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser-recovery-1.rs b/src/test/ui/parser-recovery-1.rs
index 21d3604..8126525 100644
--- a/src/test/ui/parser-recovery-1.rs
+++ b/src/test/ui/parser-recovery-1.rs
@@ -3,6 +3,7 @@
 // Test that we can recover from missing braces in the parser.
 
 trait Foo {
+//~^ ERROR `main` function not found
     fn bar() {
         let x = foo();
         //~^ ERROR cannot find function `foo` in this scope
diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr
index c29f427..ffe2b33 100644
--- a/src/test/ui/parser-recovery-1.stderr
+++ b/src/test/ui/parser-recovery-1.stderr
@@ -1,8 +1,9 @@
 error: this file contains an un-closed delimiter
-  --> $DIR/parser-recovery-1.rs:15:55
+  --> $DIR/parser-recovery-1.rs:16:55
    |
 LL | trait Foo {
    |           - un-closed delimiter
+LL |
 LL |     fn bar() {
    |              - this delimiter might not be properly closed...
 ...
@@ -13,26 +14,34 @@
    |                                                       ^
 
 error: unexpected token: `;`
-  --> $DIR/parser-recovery-1.rs:12:15
+  --> $DIR/parser-recovery-1.rs:13:15
    |
 LL |     let x = y.;
    |               ^
 
 error[E0425]: cannot find function `foo` in this scope
-  --> $DIR/parser-recovery-1.rs:7:17
+  --> $DIR/parser-recovery-1.rs:8:17
    |
 LL |         let x = foo();
    |                 ^^^ not found in this scope
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/parser-recovery-1.rs:12:13
+  --> $DIR/parser-recovery-1.rs:13:13
    |
 LL |     let x = y.;
    |             ^ not found in this scope
 
 error[E0601]: `main` function not found in crate `parser_recovery_1`
+  --> $DIR/parser-recovery-1.rs:5:1
    |
-   = note: consider adding a `main` function to `$DIR/parser-recovery-1.rs`
+LL | / trait Foo {
+LL | |
+LL | |     fn bar() {
+LL | |         let x = foo();
+...  |
+LL | |
+LL | | }
+   | |______________________________________________________^ consider adding a `main` function to `$DIR/parser-recovery-1.rs`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/parser/issue-2354.rs b/src/test/ui/parser/issue-2354.rs
index 565f848..a14eb6e 100644
--- a/src/test/ui/parser/issue-2354.rs
+++ b/src/test/ui/parser/issue-2354.rs
@@ -1,4 +1,7 @@
 fn foo() { //~ NOTE un-closed delimiter
+//~^ ERROR `main` function not found
+//~^^ NOTE main function must be defined
+//~^^^ NOTE you have one or more functions
   match Some(10) {
   //~^ NOTE this delimiter might not be properly closed...
       Some(y) => { panic!(); }
@@ -11,5 +14,5 @@
     while (i < 1000) {}
 }
 
-fn main() {} //~ NOTE here is a function named 'main'
+fn main() {} //~ NOTE here is a function named `main`
              //~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/ui/parser/issue-2354.stderr b/src/test/ui/parser/issue-2354.stderr
index 7098da7..038e3dc 100644
--- a/src/test/ui/parser/issue-2354.stderr
+++ b/src/test/ui/parser/issue-2354.stderr
@@ -1,8 +1,9 @@
 error: this file contains an un-closed delimiter
-  --> $DIR/issue-2354.rs:15:66
+  --> $DIR/issue-2354.rs:18:66
    |
 LL | fn foo() {
    |          - un-closed delimiter
+...
 LL |   match Some(10) {
    |                  - this delimiter might not be properly closed...
 ...
@@ -13,13 +14,24 @@
    |                                                                  ^
 
 error[E0601]: `main` function not found in crate `issue_2354`
+  --> $DIR/issue-2354.rs:1:1
    |
-   = note: the main function must be defined at the crate level but you have one or more functions named 'main' that are not defined at the crate level. Either move the definition or attach the `#[main]` attribute to override this behavior.
-note: here is a function named 'main'
-  --> $DIR/issue-2354.rs:14:1
+LL | / fn foo() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | | fn main() {}
+LL | |
+   | |_________________________________________________________________^ the main function must be defined at the crate level (in `$DIR/issue-2354.rs`)
+   |
+note: here is a function named `main`
+  --> $DIR/issue-2354.rs:17:1
    |
 LL | fn main() {}
    | ^^^^^^^^^^^^
+   = note: you have one or more functions named `main` not defined at the crate level
+   = help: either move the `main` function definitions or attach the `#[main]` attribute to one of them
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/lex-bad-char-literals-2.rs b/src/test/ui/parser/lex-bad-char-literals-2.rs
index 1e180f8..d35dafd 100644
--- a/src/test/ui/parser/lex-bad-char-literals-2.rs
+++ b/src/test/ui/parser/lex-bad-char-literals-2.rs
@@ -2,3 +2,5 @@
 static c: char =
     'nope' //~ ERROR: character literal may only contain one codepoint
 ;
+
+fn main() {}
diff --git a/src/test/ui/parser/lex-bad-char-literals-2.stderr b/src/test/ui/parser/lex-bad-char-literals-2.stderr
index b0a4ed0..5653d4e 100644
--- a/src/test/ui/parser/lex-bad-char-literals-2.stderr
+++ b/src/test/ui/parser/lex-bad-char-literals-2.stderr
@@ -8,10 +8,5 @@
 LL |     "nope"
    |     ^^^^^^
 
-error[E0601]: `main` function not found in crate `lex_bad_char_literals_2`
-   |
-   = note: consider adding a `main` function to `$DIR/lex-bad-char-literals-2.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
index 633c63b..818f61b 100644
--- a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
+++ b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
@@ -1,5 +1,5 @@
 error: incorrect close delimiter: `}`
-  --> $DIR/unclosed_delim_mod.rs:5:1
+  --> $DIR/unclosed_delim_mod.rs:7:1
    |
 LL | pub fn new() -> Result<Value, ()> {
    |                                   - close delimiter possibly meant for this
diff --git a/src/test/ui/parser/unclosed_delim_mod.rs b/src/test/ui/parser/unclosed_delim_mod.rs
index b1664f4..486e233 100644
--- a/src/test/ui/parser/unclosed_delim_mod.rs
+++ b/src/test/ui/parser/unclosed_delim_mod.rs
@@ -1,3 +1,5 @@
+fn main() {}
+
 pub struct Value {}
 pub fn new() -> Result<Value, ()> {
     Ok(Value {
diff --git a/src/test/ui/parser/unclosed_delim_mod.stderr b/src/test/ui/parser/unclosed_delim_mod.stderr
index cc04eb5..fe2d968 100644
--- a/src/test/ui/parser/unclosed_delim_mod.stderr
+++ b/src/test/ui/parser/unclosed_delim_mod.stderr
@@ -1,5 +1,5 @@
 error: incorrect close delimiter: `}`
-  --> $DIR/unclosed_delim_mod.rs:5:1
+  --> $DIR/unclosed_delim_mod.rs:7:1
    |
 LL | pub fn new() -> Result<Value, ()> {
    |                                   - close delimiter possibly meant for this
@@ -9,10 +9,5 @@
 LL | }
    | ^ incorrect close delimiter
 
-error[E0601]: `main` function not found in crate `unclosed_delim_mod`
-   |
-   = note: consider adding a `main` function to `$DIR/unclosed_delim_mod.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/proc-macro/derive-still-gated.rs b/src/test/ui/proc-macro/derive-still-gated.rs
index 4e6f9b0..3f8d6f0 100644
--- a/src/test/ui/proc-macro/derive-still-gated.rs
+++ b/src/test/ui/proc-macro/derive-still-gated.rs
@@ -3,7 +3,7 @@
 #[macro_use]
 extern crate test_macros;
 
-#[derive_Empty] //~ ERROR cannot find attribute macro `derive_Empty` in this scope
+#[derive_Empty] //~ ERROR cannot find attribute `derive_Empty` in this scope
 struct A;
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/derive-still-gated.stderr b/src/test/ui/proc-macro/derive-still-gated.stderr
index 4df1715..99289fd 100644
--- a/src/test/ui/proc-macro/derive-still-gated.stderr
+++ b/src/test/ui/proc-macro/derive-still-gated.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `derive_Empty` in this scope
+error: cannot find attribute `derive_Empty` in this scope
   --> $DIR/derive-still-gated.rs:6:3
    |
 LL | #[derive_Empty]
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
index c9881ad..94a4b40 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
@@ -3,6 +3,11 @@
 // FIXME https://github.com/rust-lang/rust/issues/59998
 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
index 40333a3..107f5fb 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-1.rs:10:1
+  --> $DIR/invalid-punct-ident-1.rs:15:1
    |
 LL | invalid_punct!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
index 15e2286..778b7ee 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
@@ -3,6 +3,11 @@
 // FIXME https://github.com/rust-lang/rust/issues/59998
 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
index ec97e26..f1b9ecc 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-2.rs:10:1
+  --> $DIR/invalid-punct-ident-2.rs:15:1
    |
 LL | invalid_ident!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
index 629bbaa..f68ee3d 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
@@ -3,6 +3,11 @@
 // FIXME https://github.com/rust-lang/rust/issues/59998
 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
index a5e5ded..6044b98 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-3.rs:10:1
+  --> $DIR/invalid-punct-ident-3.rs:15:1
    |
 LL | invalid_raw_ident!();
    | ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
index 8a26df9..b17c056 100644
--- a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
+++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
@@ -25,17 +25,17 @@
     my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it
 }
 fn check_bang2() {
-    my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr!` in this scope
+    my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr` in this scope
     crate::my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines
                              //~| ERROR expected macro, found attribute macro `crate::my_macro_attr`
 }
 fn check_bang3() {
-    MyTrait!(); //~ ERROR cannot find macro `MyTrait!` in this scope
+    MyTrait!(); //~ ERROR cannot find macro `MyTrait` in this scope
     crate::MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it
                        //~| ERROR expected macro, found derive macro `crate::MyTrait`
 }
 
-#[my_macro] //~ ERROR cannot find attribute macro `my_macro` in this scope
+#[my_macro] //~ ERROR cannot find attribute `my_macro` in this scope
 #[crate::my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
                    //~| ERROR expected attribute, found macro `crate::my_macro`
 fn check_attr1() {}
diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
index 0c863e9..c011a70 100644
--- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
+++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
@@ -88,19 +88,19 @@
 LL | #[derive(crate::my_macro)]
    |          ^^^^^^^^^^^^^^^ not a derive macro
 
-error: cannot find macro `my_macro_attr!` in this scope
+error: cannot find macro `my_macro_attr` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:28:5
    |
 LL |     my_macro_attr!();
    |     ^^^^^^^^^^^^^
 
-error: cannot find macro `MyTrait!` in this scope
+error: cannot find macro `MyTrait` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:33:5
    |
 LL |     MyTrait!();
    |     ^^^^^^^
 
-error: cannot find attribute macro `my_macro` in this scope
+error: cannot find attribute `my_macro` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:38:3
    |
 LL | #[my_macro]
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.rs b/src/test/ui/proc-macro/proc-macro-attributes.rs
index 0421522..6401522 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.rs
+++ b/src/test/ui/proc-macro/proc-macro-attributes.rs
@@ -4,7 +4,7 @@
 extern crate derive_b;
 
 #[B] //~ ERROR `B` is ambiguous
-#[C] //~ ERROR cannot find attribute macro `C` in this scope
+#[C] //~ ERROR cannot find attribute `C` in this scope
 #[B(D)] //~ ERROR `B` is ambiguous
 #[B(E = "foo")] //~ ERROR `B` is ambiguous
 #[B(arbitrary tokens)] //~ ERROR `B` is ambiguous
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.stderr b/src/test/ui/proc-macro/proc-macro-attributes.stderr
index b068c6b..3ac93a7 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.stderr
+++ b/src/test/ui/proc-macro/proc-macro-attributes.stderr
@@ -1,4 +1,4 @@
-error: cannot find attribute macro `C` in this scope
+error: cannot find attribute `C` in this scope
   --> $DIR/proc-macro-attributes.rs:7:3
    |
 LL | #[C]
diff --git a/src/test/ui/proc-macro/proc-macro-gates2.rs b/src/test/ui/proc-macro/proc-macro-gates2.rs
index 35d7fc8..2fd5efd 100644
--- a/src/test/ui/proc-macro/proc-macro-gates2.rs
+++ b/src/test/ui/proc-macro/proc-macro-gates2.rs
@@ -10,11 +10,11 @@
 // should either require a feature gate or not be allowed on stable.
 
 fn _test6<#[empty_attr] T>() {}
-//~^ ERROR: unknown to the compiler
+//~^ ERROR: expected an inert attribute, found an attribute macro
 
 fn _test7() {
     match 1 {
-        #[empty_attr] //~ ERROR: unknown to the compiler
+        #[empty_attr] //~ ERROR: expected an inert attribute, found an attribute macro
         0 => {}
         _ => {}
     }
diff --git a/src/test/ui/proc-macro/proc-macro-gates2.stderr b/src/test/ui/proc-macro/proc-macro-gates2.stderr
index a7f6f8b..fd271da 100644
--- a/src/test/ui/proc-macro/proc-macro-gates2.stderr
+++ b/src/test/ui/proc-macro/proc-macro-gates2.stderr
@@ -1,21 +1,14 @@
-error[E0658]: the attribute `empty_attr` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-gates2.rs:12:11
    |
 LL | fn _test6<#[empty_attr] T>() {}
    |           ^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `empty_attr` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-gates2.rs:17:9
    |
 LL |         #[empty_attr]
    |         ^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/proc-macro/resolve-error.rs b/src/test/ui/proc-macro/resolve-error.rs
index 0a7861a..d2282af 100644
--- a/src/test/ui/proc-macro/resolve-error.rs
+++ b/src/test/ui/proc-macro/resolve-error.rs
@@ -23,12 +23,12 @@
 //~^ ERROR cannot find
 struct Foo;
 
-// Interpreted as a feature gated custom attribute
-#[attr_proc_macra] //~ ERROR cannot find attribute macro `attr_proc_macra` in this scope
+// Interpreted as an unstable custom attribute
+#[attr_proc_macra] //~ ERROR cannot find attribute `attr_proc_macra` in this scope
 struct Bar;
 
-// Interpreted as a feature gated custom attribute
-#[FooWithLongNan] //~ ERROR cannot find attribute macro `FooWithLongNan` in this scope
+// Interpreted as an unstable custom attribute
+#[FooWithLongNan] //~ ERROR cannot find attribute `FooWithLongNan` in this scope
 struct Asdf;
 
 #[derive(Dlone)]
diff --git a/src/test/ui/proc-macro/resolve-error.stderr b/src/test/ui/proc-macro/resolve-error.stderr
index 2a5f2b8..3dca5ce 100644
--- a/src/test/ui/proc-macro/resolve-error.stderr
+++ b/src/test/ui/proc-macro/resolve-error.stderr
@@ -1,22 +1,22 @@
-error: cannot find macro `bang_proc_macrp!` in this scope
+error: cannot find macro `bang_proc_macrp` in this scope
   --> $DIR/resolve-error.rs:56:5
    |
 LL |     bang_proc_macrp!();
    |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro`
 
-error: cannot find macro `Dlona!` in this scope
+error: cannot find macro `Dlona` in this scope
   --> $DIR/resolve-error.rs:53:5
    |
 LL |     Dlona!();
    |     ^^^^^
 
-error: cannot find macro `attr_proc_macra!` in this scope
+error: cannot find macro `attr_proc_macra` in this scope
   --> $DIR/resolve-error.rs:50:5
    |
 LL |     attr_proc_macra!();
    |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac`
 
-error: cannot find macro `FooWithLongNama!` in this scope
+error: cannot find macro `FooWithLongNama` in this scope
   --> $DIR/resolve-error.rs:47:5
    |
 LL |     FooWithLongNama!();
@@ -40,13 +40,13 @@
 LL | #[derive(Dlone)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clone`
 
-error: cannot find attribute macro `FooWithLongNan` in this scope
+error: cannot find attribute `FooWithLongNan` in this scope
   --> $DIR/resolve-error.rs:31:3
    |
 LL | #[FooWithLongNan]
    |   ^^^^^^^^^^^^^^
 
-error: cannot find attribute macro `attr_proc_macra` in this scope
+error: cannot find attribute `attr_proc_macra` in this scope
   --> $DIR/resolve-error.rs:27:3
    |
 LL | #[attr_proc_macra]
diff --git a/src/test/ui/refutable-pattern-errors.rs b/src/test/ui/refutable-pattern-errors.rs
index aa5fa76..d4afe17 100644
--- a/src/test/ui/refutable-pattern-errors.rs
+++ b/src/test/ui/refutable-pattern-errors.rs
@@ -1,7 +1,9 @@
+// ignore-tidy-linelength
+
 fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
 //~^ ERROR refutable pattern in function argument: `(_, _)` not covered
 
 fn main() {
     let (1, (Some(1), 2..=3)) = (1, (None, 2));
-    //~^ ERROR refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` not covered
+    //~^ ERROR refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered
 }
diff --git a/src/test/ui/refutable-pattern-errors.stderr b/src/test/ui/refutable-pattern-errors.stderr
index c67ae7c..3b13e25 100644
--- a/src/test/ui/refutable-pattern-errors.stderr
+++ b/src/test/ui/refutable-pattern-errors.stderr
@@ -1,14 +1,14 @@
 error[E0005]: refutable pattern in function argument: `(_, _)` not covered
-  --> $DIR/refutable-pattern-errors.rs:1:9
+  --> $DIR/refutable-pattern-errors.rs:3:9
    |
 LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
    |         ^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
 
-error[E0005]: refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` not covered
-  --> $DIR/refutable-pattern-errors.rs:5:9
+error[E0005]: refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered
+  --> $DIR/refutable-pattern-errors.rs:7:9
    |
 LL |     let (1, (Some(1), 2..=3)) = (1, (None, 2));
-   |         ^^^^^^^^^^^^^^^^^^^^^ pattern `(std::i32::MIN..=0i32, _)` not covered
+   |         ^^^^^^^^^^^^^^^^^^^^^ patterns `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/reserved/reserved-attr-on-macro.rs b/src/test/ui/reserved/reserved-attr-on-macro.rs
index fddb991..2630db0 100644
--- a/src/test/ui/reserved/reserved-attr-on-macro.rs
+++ b/src/test/ui/reserved/reserved-attr-on-macro.rs
@@ -1,5 +1,5 @@
 #[rustc_attribute_should_be_reserved]
-//~^ ERROR cannot find attribute macro `rustc_attribute_should_be_reserved` in this scope
+//~^ ERROR cannot find attribute `rustc_attribute_should_be_reserved` in this scope
 //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 
 macro_rules! foo {
diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr
index 856162b..6859605 100644
--- a/src/test/ui/reserved/reserved-attr-on-macro.stderr
+++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr
@@ -15,7 +15,7 @@
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: cannot find attribute macro `rustc_attribute_should_be_reserved` in this scope
+error: cannot find attribute `rustc_attribute_should_be_reserved` in this scope
   --> $DIR/reserved-attr-on-macro.rs:1:3
    |
 LL | #[rustc_attribute_should_be_reserved]
diff --git a/src/test/ui/resolve/visibility-indeterminate.rs b/src/test/ui/resolve/visibility-indeterminate.rs
index 595eaf4..0e1142d 100644
--- a/src/test/ui/resolve/visibility-indeterminate.rs
+++ b/src/test/ui/resolve/visibility-indeterminate.rs
@@ -1,5 +1,7 @@
 // edition:2018
 
-foo!(); //~ ERROR cannot find macro `foo!` in this scope
+foo!(); //~ ERROR cannot find macro `foo` in this scope
 
 pub(in ::bar) struct Baz {} //~ ERROR cannot determine resolution for the visibility
+
+fn main() {}
diff --git a/src/test/ui/resolve/visibility-indeterminate.stderr b/src/test/ui/resolve/visibility-indeterminate.stderr
index a259c80..b967829 100644
--- a/src/test/ui/resolve/visibility-indeterminate.stderr
+++ b/src/test/ui/resolve/visibility-indeterminate.stderr
@@ -4,16 +4,11 @@
 LL | pub(in ::bar) struct Baz {}
    |        ^^^^^
 
-error: cannot find macro `foo!` in this scope
+error: cannot find macro `foo` in this scope
   --> $DIR/visibility-indeterminate.rs:3:1
    |
 LL | foo!();
    | ^^^
 
-error[E0601]: `main` function not found in crate `visibility_indeterminate`
-   |
-   = note: consider adding a `main` function to `$DIR/visibility-indeterminate.rs`
+error: aborting due to 2 previous errors
 
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs
index e43c8541e6..1e08616 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs
@@ -4,15 +4,13 @@
 
 // run-pass
 
-#![feature(bind_by_move_pattern_guards)]
-
 use std::sync::mpsc::channel;
 
 fn main() {
     let (tx, rx) = channel();
     let x = Some(rx);
-    tx.send(false);
-    tx.send(false);
+    tx.send(false).unwrap();
+    tx.send(false).unwrap();
     match x {
         Some(z) if z.recv().unwrap() => { panic!() },
         Some(z) => { assert!(!z.recv().unwrap()); },
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr
deleted file mode 100644
index fe1f699..0000000
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: compilation successful
-  --> $DIR/feature-gate.rs:36:1
-   |
-LL | / fn main() {
-LL | |     foo(107)
-LL | | }
-   | |_^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr
deleted file mode 100644
index fe1f699..0000000
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: compilation successful
-  --> $DIR/feature-gate.rs:36:1
-   |
-LL | / fn main() {
-LL | |     foo(107)
-LL | | }
-   | |_^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr
deleted file mode 100644
index 34e8b0e..0000000
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: compilation successful
-  --> $DIR/feature-gate.rs:41:1
-   |
-LL | / fn main() {
-LL | |     foo(107)
-LL | | }
-   | |_^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr
deleted file mode 100644
index 34e8b0e..0000000
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: compilation successful
-  --> $DIR/feature-gate.rs:41:1
-   |
-LL | / fn main() {
-LL | |     foo(107)
-LL | | }
-   | |_^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr
deleted file mode 100644
index 7a7b1c2..0000000
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0008]: cannot bind by-move into a pattern guard
-  --> $DIR/feature-gate.rs:28:16
-   |
-LL |         A { a: v } if *v == 42 => v,
-   |                ^ moves value into pattern guard
-   |
-   = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0008`.
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs
deleted file mode 100644
index 69fce0b..0000000
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Check that pattern-guards with move-bound variables is only allowed
-// with the appropriate set of feature gates. (Note that we require
-// the code to opt into MIR-borrowck in *some* way before the feature
-// will work; we use the revision system here to enumerate a number of
-// ways that opt-in could occur.)
-
-// gate-test-bind_by_move_pattern_guards
-
-// revisions: no_gate gate_and_2015 gate_and_2018
-
-// (We're already testing NLL behavior quite explicitly, no need for compare-mode=nll.)
-// ignore-compare-mode-nll
-
-#![feature(rustc_attrs)]
-
-#![cfg_attr(gate_and_2015, feature(bind_by_move_pattern_guards))]
-#![cfg_attr(gate_and_2018, feature(bind_by_move_pattern_guards))]
-
-//[gate_and_2015] edition:2015
-//[gate_and_2018] edition:2018
-
-struct A { a: Box<i32> }
-
-fn foo(n: i32) {
-    let x = A { a: Box::new(n) };
-    let _y = match x {
-
-        A { a: v } if *v == 42 => v,
-        //[no_gate]~^ ERROR cannot bind by-move into a pattern guard
-
-        _ => Box::new(0)
-    };
-}
-
-#[rustc_error]
-fn main() {
-    foo(107)
-}
-//[gate_and_2015]~^^^ ERROR compilation successful
-//[gate_and_2018]~^^^^ ERROR compilation successful
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/former-E0008-now-pass.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/former-E0008-now-pass.rs
new file mode 100644
index 0000000..3161d6f
--- /dev/null
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/former-E0008-now-pass.rs
@@ -0,0 +1,11 @@
+// This test used to emit E0008 but now passed since `bind_by_move_pattern_guards`
+// have been stabilized.
+
+// check-pass
+
+fn main() {
+    match Some("hi".to_string()) {
+        Some(s) if s.len() == 0 => {},
+        _ => {},
+    }
+}
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs
index eccb4e41..b716fc8 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs
@@ -1,5 +1,3 @@
-#![feature(bind_by_move_pattern_guards)]
-
 // run-pass
 
 struct A { a: Box<i32> }
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
index 602a8e1..d1f685f 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
@@ -1,5 +1,3 @@
-#![feature(bind_by_move_pattern_guards)]
-
 enum VecWrapper { A(Vec<i32>) }
 
 fn foo(x: VecWrapper) -> usize {
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
index c9e8fc8..7becd01 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-across-arms.rs:7:36
+  --> $DIR/rfc-reject-double-move-across-arms.rs:5:36
    |
 LL |         VecWrapper::A(v) if { drop(v); false } => 1,
    |                                    ^ move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
index 77252a1..571f51c 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
@@ -1,5 +1,3 @@
-#![feature(bind_by_move_pattern_guards)]
-
 struct A { a: Box<i32> }
 
 fn foo(n: i32) {
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
index a345022..b93e721 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
    |
 LL |         A { a: v } if { drop(v); true } => v,
    |                              ^ move occurs because `v` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
index 470a5ea..fe7df44 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
@@ -10,11 +10,11 @@
 
 fn main() {
     let variant_tuple = NonExhaustiveVariants::Tuple(340);
-    let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
+    let _variant_struct = NonExhaustiveVariants::Struct { field: 340 };
 
     match variant_tuple {
         NonExhaustiveVariants::Unit => "",
-        NonExhaustiveVariants::Tuple(fe_tpl) => "",
-        NonExhaustiveVariants::Struct { field } => ""
+        NonExhaustiveVariants::Tuple(_fe_tpl) => "",
+        NonExhaustiveVariants::Struct { field: _ } => ""
     };
 }
diff --git a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs
index 1de4e5b..b95105b 100644
--- a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs
@@ -2,8 +2,6 @@
 
 #![allow(irrefutable_let_patterns)]
 
-use std::ops::Range;
-
 fn main() {
     let x: bool;
     // This should associate as: `(x = (true && false));`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr
new file mode 100644
index 0000000..be7ef65
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr
@@ -0,0 +1,8 @@
+warning: unreachable block in `if` expression
+  --> $DIR/protect-precedences.rs:13:41
+   |
+LL |         if let _ = return true && false {};
+   |                                         ^^
+   |
+   = note: `#[warn(unreachable_code)]` on by default
+
diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
index b957c67..a8fe5d6 100644
--- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
+++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
@@ -5,7 +5,7 @@
         /// Foo
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+        //~^ ERROR expected an inert attribute, found an attribute macro
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -21,7 +21,7 @@
     /// Foo
     //~^ ERROR documentation comments cannot be applied to function
     #[test] a: u32,
-    //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+    //~^ ERROR expected an inert attribute, found an attribute macro
     /// Bar
     //~^ ERROR documentation comments cannot be applied to function
     #[must_use]
@@ -36,7 +36,7 @@
     /// Foo
     //~^ ERROR documentation comments cannot be applied to function
     #[test] a: u32,
-    //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+    //~^ ERROR expected an inert attribute, found an attribute macro
     /// Bar
     //~^ ERROR documentation comments cannot be applied to function
     #[must_use]
@@ -56,7 +56,7 @@
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+        //~^ ERROR expected an inert attribute, found an attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -77,7 +77,7 @@
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+        //~^ ERROR expected an inert attribute, found an attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -96,7 +96,7 @@
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+        //~^ ERROR expected an inert attribute, found an attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -115,7 +115,7 @@
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+        //~^ ERROR expected an inert attribute, found an attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -132,7 +132,7 @@
         /// Foo
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: u32,
-        //~^ ERROR the attribute `test` is currently unknown to the compiler and may have
+        //~^ ERROR expected an inert attribute, found an attribute macro
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
index a57572a..8ab3fc3 100644
--- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
+++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
@@ -1,3 +1,51 @@
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:7:9
+   |
+LL |         #[test] a: i32,
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:23:5
+   |
+LL |     #[test] a: u32,
+   |     ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:38:5
+   |
+LL |     #[test] a: u32,
+   |     ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:58:9
+   |
+LL |         #[test] a: i32,
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:79:9
+   |
+LL |         #[test] a: i32,
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:98:9
+   |
+LL |         #[test] a: i32,
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:117:9
+   |
+LL |         #[test] a: i32,
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:134:9
+   |
+LL |         #[test] a: u32,
+   |         ^^^^^^^
+
 error: documentation comments cannot be applied to function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:5:9
    |
@@ -262,78 +310,5 @@
 LL |         #[no_mangle] b: i32
    |         ^^^^^^^^^^^^
 
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:7:9
-   |
-LL |         #[test] a: i32,
-   |         ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:23:5
-   |
-LL |     #[test] a: u32,
-   |     ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:38:5
-   |
-LL |     #[test] a: u32,
-   |     ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:58:9
-   |
-LL |         #[test] a: i32,
-   |         ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:79:9
-   |
-LL |         #[test] a: i32,
-   |         ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:98:9
-   |
-LL |         #[test] a: i32,
-   |         ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:117:9
-   |
-LL |         #[test] a: i32,
-   |         ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error[E0658]: the attribute `test` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/param-attrs-builtin-attrs.rs:134:9
-   |
-LL |         #[test] a: u32,
-   |         ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
 error: aborting due to 52 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs
index 8defa26..7f00308 100644
--- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs
+++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs
@@ -9,52 +9,52 @@
 struct W(u8);
 
 extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
-//~^ ERROR the attribute `id` is currently unknown to the compiler
-//~| ERROR the attribute `id` is currently unknown to the compiler
+//~^ ERROR expected an inert attribute, found an attribute macro
+//~| ERROR expected an inert attribute, found an attribute macro
 
 unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {}
-//~^ ERROR the attribute `id` is currently unknown to the compiler
+//~^ ERROR expected an inert attribute, found an attribute macro
 
 type Alias = extern "C" fn(#[id] u8, #[id] ...);
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
 
 fn free(#[id] arg1: u8) {
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
     let lam = |#[id] W(x), #[id] y| ();
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
 }
 
 impl W {
     fn inherent1(#[id] self, #[id] arg1: u8) {}
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
     fn inherent2(#[id] &self, #[id] arg1: u8) {}
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
     fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
 }
 
 trait A {
     fn trait1(#[id] self, #[id] arg1: u8);
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
     fn trait2(#[id] &self, #[id] arg1: u8);
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
-    //~^ ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
-    //~| ERROR the attribute `id` is currently unknown to the compiler
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr
index 69b9a46..3b72e8a 100644
--- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr
+++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr
@@ -1,228 +1,152 @@
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:11:21
    |
 LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
    |                     ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:11:38
    |
 LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
    |                                      ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:15:38
    |
 LL | unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {}
    |                                      ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:18:28
    |
 LL | type Alias = extern "C" fn(#[id] u8, #[id] ...);
    |                            ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:18:38
    |
 LL | type Alias = extern "C" fn(#[id] u8, #[id] ...);
    |                                      ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:22:9
    |
 LL | fn free(#[id] arg1: u8) {
    |         ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:24:16
    |
 LL |     let lam = |#[id] W(x), #[id] y| ();
    |                ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:24:28
    |
 LL |     let lam = |#[id] W(x), #[id] y| ();
    |                            ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:30:18
    |
 LL |     fn inherent1(#[id] self, #[id] arg1: u8) {}
    |                  ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:30:30
    |
 LL |     fn inherent1(#[id] self, #[id] arg1: u8) {}
    |                              ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:33:18
    |
 LL |     fn inherent2(#[id] &self, #[id] arg1: u8) {}
    |                  ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:33:31
    |
 LL |     fn inherent2(#[id] &self, #[id] arg1: u8) {}
    |                               ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:36:22
    |
 LL |     fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
    |                      ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:36:42
    |
 LL |     fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
    |                                          ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:39:22
    |
 LL |     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
    |                      ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:39:45
    |
 LL |     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
    |                                             ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:45:15
    |
 LL |     fn trait1(#[id] self, #[id] arg1: u8);
    |               ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:45:27
    |
 LL |     fn trait1(#[id] self, #[id] arg1: u8);
    |                           ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:48:15
    |
 LL |     fn trait2(#[id] &self, #[id] arg1: u8);
    |               ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:48:28
    |
 LL |     fn trait2(#[id] &self, #[id] arg1: u8);
    |                            ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:51:19
    |
 LL |     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
    |                   ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:51:39
    |
 LL |     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
    |                                       ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:54:19
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
    |                   ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:54:42
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
    |                                          ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: the attribute `id` is currently unknown to the compiler and may have meaning added to it in the future
+error: expected an inert attribute, found an attribute macro
   --> $DIR/proc-macro-cannot-be-used.rs:54:58
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
    |                                                          ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 25 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs b/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs
new file mode 100644
index 0000000..5b378fb
--- /dev/null
+++ b/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs
@@ -0,0 +1,135 @@
+// run-pass
+
+// This file checks that fn ptrs are considered structurally matchable.
+// See also rust-lang/rust#63479.
+
+fn main() {
+    let mut count = 0;
+
+    // A type which is not structurally matchable:
+    struct NotSM;
+
+    // And one that is:
+    #[derive(PartialEq, Eq)]
+    struct SM;
+
+    fn trivial() {}
+
+    fn sm_to(_: SM) {}
+    fn not_sm_to(_: NotSM) {}
+    fn to_sm() -> SM { SM }
+    fn to_not_sm() -> NotSM { NotSM }
+
+    // To recreate the scenario of interest in #63479, we need to add
+    // a ref-level-of-indirection so that we descend into the type.
+
+    fn r_sm_to(_: &SM) {}
+    fn r_not_sm_to(_: &NotSM) {}
+    fn r_to_r_sm(_: &()) -> &SM { &SM }
+    fn r_to_r_not_sm(_: &()) -> &NotSM { &NotSM }
+
+    #[derive(PartialEq, Eq)]
+    struct Wrap<T>(T);
+
+    // In the code below, we put the match input into a local so that
+    // we can assign it an explicit type that is an fn ptr instead of
+    // a singleton type of the fn itself that the type inference would
+    // otherwise assign.
+
+    // Check that fn() is #[structural_match]
+    const CFN1: Wrap<fn()> = Wrap(trivial);
+    let input: Wrap<fn()> = Wrap(trivial);
+    match Wrap(input) {
+        Wrap(CFN1) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(T) is #[structural_match] when T is too.
+    const CFN2: Wrap<fn(SM)> = Wrap(sm_to);
+    let input: Wrap<fn(SM)> = Wrap(sm_to);
+    match Wrap(input) {
+        Wrap(CFN2) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> T is #[structural_match] when T is too.
+    const CFN3: Wrap<fn() -> SM> = Wrap(to_sm);
+    let input: Wrap<fn() -> SM> = Wrap(to_sm);
+    match Wrap(input) {
+        Wrap(CFN3) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(T) is #[structural_match] even if T is not.
+    const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to);
+    let input: Wrap<fn(NotSM)> = Wrap(not_sm_to);
+    match Wrap(input) {
+        Wrap(CFN4) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> T is #[structural_match] even if T is not.
+    const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
+    let input: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
+    match Wrap(input) {
+        Wrap(CFN5) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(&T) is #[structural_match] when T is too.
+    const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
+    let input: Wrap<fn(&SM)> = Wrap(r_sm_to);
+    match Wrap(input) {
+        Wrap(CFN6) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> &T is #[structural_match] when T is too.
+    const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
+    let input: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
+    match Wrap(input) {
+        Wrap(CFN7) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn(T) is #[structural_match] even if T is not.
+    const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
+    let input: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
+    match Wrap(input) {
+        Wrap(CFN8) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that fn() -> T is #[structural_match] even if T is not.
+    const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
+    let input: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
+    match Wrap(input) {
+        Wrap(CFN9) => count += 1,
+        Wrap(_) => {}
+    };
+
+    // Check that a type which has fn ptrs is `#[structural_match]`.
+    #[derive(PartialEq, Eq)]
+    struct Foo {
+        alpha: fn(NotSM),
+        beta: fn() -> NotSM,
+        gamma: fn(SM),
+        delta: fn() -> SM,
+    }
+
+    const CFOO: Foo = Foo {
+        alpha: not_sm_to,
+        beta: to_not_sm,
+        gamma: sm_to,
+        delta: to_sm,
+    };
+
+    let input = Foo { alpha: not_sm_to, beta: to_not_sm, gamma: sm_to, delta: to_sm };
+    match input {
+        CFOO => count += 1,
+        Foo { .. } => {}
+    };
+
+    // Final count must be 10 now if all
+    assert_eq!(count, 10);
+}
diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs
new file mode 100644
index 0000000..b3c91ce
--- /dev/null
+++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs
@@ -0,0 +1,36 @@
+// run-pass
+
+// The actual regression test from #63479. (Including this because my
+// first draft at fn-ptr-is-structurally-matchable.rs failed to actually
+// cover the case this hit; I've since expanded it accordingly, but the
+// experience left me wary of leaving this regression test out.)
+
+#[derive(Eq)]
+struct A {
+  a: i64
+}
+
+impl PartialEq for A {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.a.eq(&other.a)
+    }
+}
+
+type Fn = fn(&[A]);
+
+fn my_fn(_args: &[A]) {
+  println!("hello world");
+}
+
+const TEST: Fn = my_fn;
+
+struct B(Fn);
+
+fn main() {
+  let s = B(my_fn);
+  match s {
+    B(TEST) => println!("matched"),
+    _ => panic!("didn't match")
+  };
+}
diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr
index a811812..19f758f 100644
--- a/src/test/ui/rust-2018/trait-import-suggestions.stderr
+++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr
@@ -2,7 +2,7 @@
   --> $DIR/trait-import-suggestions.rs:22:11
    |
 LL |         x.foobar();
-   |           ^^^^^^
+   |           ^^^^^^ method not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
@@ -12,7 +12,7 @@
   --> $DIR/trait-import-suggestions.rs:28:7
    |
 LL |     x.bar();
-   |       ^^^
+   |       ^^^ method not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
@@ -24,7 +24,7 @@
   --> $DIR/trait-import-suggestions.rs:29:7
    |
 LL |     x.baz();
-   |       ^^^
+   |       ^^^ method not found in `u32`
 
 error[E0599]: no function or associated item named `from_str` found for type `u32` in the current scope
   --> $DIR/trait-import-suggestions.rs:30:18
diff --git a/src/test/ui/rust-2018/uniform-paths/deadlock.rs b/src/test/ui/rust-2018/uniform-paths/deadlock.rs
index 3228d79..83ed70a 100644
--- a/src/test/ui/rust-2018/uniform-paths/deadlock.rs
+++ b/src/test/ui/rust-2018/uniform-paths/deadlock.rs
@@ -1,7 +1,7 @@
 // edition:2018
 // compile-flags:--extern foo --extern bar
 
-use foo::bar; //~ ERROR unresolved import
+use foo::bar; //~ ERROR can't find crate for `foo`
 use bar::foo;
 
 fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr
index b4ac15c..9336e90 100644
--- a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr
+++ b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr
@@ -1,9 +1,9 @@
-error[E0432]: unresolved import
+error[E0463]: can't find crate for `foo`
   --> $DIR/deadlock.rs:4:5
    |
 LL | use foo::bar;
-   |     ^^^^^^^^
+   |     ^^^ can't find crate
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0432`.
+For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/save-analysis/issue-63663.rs b/src/test/ui/save-analysis/issue-63663.rs
new file mode 100644
index 0000000..92e8588
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-63663.rs
@@ -0,0 +1,28 @@
+// check-pass
+// compile-flags: -Zsave-analysis
+
+pub trait Trait {
+    type Assoc;
+}
+
+pub struct A;
+
+trait Generic<T> {}
+impl<T> Generic<T> for () {}
+
+// Don't ICE when resolving type paths in return type `impl Trait`
+fn assoc_in_opaque_type_bounds<U: Trait>() -> impl Generic<U::Assoc> {}
+
+// Check that this doesn't ICE when processing associated const in formal
+// argument and return type of functions defined inside function/method scope.
+pub fn func() {
+    fn _inner1<U: Trait>(_: U::Assoc) {}
+    fn _inner2<U: Trait>() -> U::Assoc { unimplemented!() }
+
+    impl A {
+        fn _inner1<U: Trait>(self, _: U::Assoc) {}
+        fn _inner2<U: Trait>(self) -> U::Assoc { unimplemented!() }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr
index 06dad7c..dec5809 100644
--- a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr
+++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr
@@ -8,7 +8,7 @@
    |        --- the method is available for `std::boxed::Box<A>` here
 ...
 LL |     A.foo();
-   |       ^^^
+   |       ^^^ method not found in `A`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
index 90cd3b8..e93c4da 100644
--- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
+++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
@@ -7,7 +7,7 @@
    | --------- method `foo` not found for this
 ...
 LL |     A.foo()
-   |       ^^^
+   |       ^^^ method not found in `A`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `foo`, perhaps you need to implement it:
diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs
index 844f13c..dfb7d65 100644
--- a/src/test/ui/self/self_type_keyword.rs
+++ b/src/test/ui/self/self_type_keyword.rs
@@ -19,7 +19,7 @@
         ref mut Self => (),
         //~^ ERROR expected identifier, found keyword `Self`
         Self!() => (),
-        //~^ ERROR cannot find macro `Self!` in this scope
+        //~^ ERROR cannot find macro `Self` in this scope
         Foo { Self } => (),
         //~^ ERROR expected identifier, found keyword `Self`
     }
diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr
index bb63119..11b3b01 100644
--- a/src/test/ui/self/self_type_keyword.stderr
+++ b/src/test/ui/self/self_type_keyword.stderr
@@ -54,7 +54,7 @@
 LL | struct Bar<'Self>;
    |            ^^^^^
 
-error: cannot find macro `Self!` in this scope
+error: cannot find macro `Self` in this scope
   --> $DIR/self_type_keyword.rs:21:9
    |
 LL |         Self!() => (),
diff --git a/src/test/ui/shadowed/shadowed-trait-methods.stderr b/src/test/ui/shadowed/shadowed-trait-methods.stderr
index e05da17..190159e 100644
--- a/src/test/ui/shadowed/shadowed-trait-methods.stderr
+++ b/src/test/ui/shadowed/shadowed-trait-methods.stderr
@@ -2,7 +2,7 @@
   --> $DIR/shadowed-trait-methods.rs:13:8
    |
 LL |     ().f()
-   |        ^
+   |        ^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
index c14fc04..bbfe4c3 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
@@ -5,7 +5,7 @@
    | ---------------- method `foo_one` not found for this
 ...
 LL |     println!("{}", MyStruct.foo_one());
-   |                             ^^^^^^^
+   |                             ^^^^^^^ method not found in `MyStruct`
    |
    = note: the method `foo_one` exists but the following trait bounds were not satisfied:
            `MyStruct : Foo`
diff --git a/src/test/ui/std-backtrace.rs b/src/test/ui/std-backtrace.rs
new file mode 100644
index 0000000..d84c493d
--- /dev/null
+++ b/src/test/ui/std-backtrace.rs
@@ -0,0 +1,75 @@
+// run-pass
+// ignore-android FIXME #17520
+// ignore-cloudabi spawning processes is not supported
+// ignore-emscripten spawning processes is not supported
+// ignore-openbsd no support for libbacktrace without filename
+// ignore-sgx no processes
+// ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
+// compile-flags:-g
+
+#![feature(backtrace)]
+
+use std::env;
+use std::process::Command;
+use std::str;
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() >= 2 && args[1] == "force" {
+        println!("{}", std::backtrace::Backtrace::force_capture());
+    } else if args.len() >= 2 {
+        println!("{}", std::backtrace::Backtrace::capture());
+    } else {
+        runtest(&args[0]);
+        println!("test ok");
+    }
+}
+
+fn runtest(me: &str) {
+    env::remove_var("RUST_BACKTRACE");
+    env::remove_var("RUST_LIB_BACKTRACE");
+
+    let p = Command::new(me).arg("a").env("RUST_BACKTRACE", "1").output().unwrap();
+    assert!(p.status.success());
+    assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
+    assert!(String::from_utf8_lossy(&p.stdout).contains("backtrace::main"));
+
+    let p = Command::new(me).arg("a").env("RUST_BACKTRACE", "0").output().unwrap();
+    assert!(p.status.success());
+    assert!(String::from_utf8_lossy(&p.stdout).contains("disabled backtrace\n"));
+
+    let p = Command::new(me).arg("a").output().unwrap();
+    assert!(p.status.success());
+    assert!(String::from_utf8_lossy(&p.stdout).contains("disabled backtrace\n"));
+
+    let p = Command::new(me)
+        .arg("a")
+        .env("RUST_LIB_BACKTRACE", "1")
+        .env("RUST_BACKTRACE", "1")
+        .output()
+        .unwrap();
+    assert!(p.status.success());
+    assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
+
+    let p = Command::new(me)
+        .arg("a")
+        .env("RUST_LIB_BACKTRACE", "0")
+        .env("RUST_BACKTRACE", "1")
+        .output()
+        .unwrap();
+    assert!(p.status.success());
+    assert!(String::from_utf8_lossy(&p.stdout).contains("disabled backtrace\n"));
+
+    let p = Command::new(me)
+        .arg("force")
+        .env("RUST_LIB_BACKTRACE", "0")
+        .env("RUST_BACKTRACE", "0")
+        .output()
+        .unwrap();
+    assert!(p.status.success());
+    assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
+
+    let p = Command::new(me).arg("force").output().unwrap();
+    assert!(p.status.success());
+    assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
+}
diff --git a/src/test/ui/suggestions/attribute-typos.rs b/src/test/ui/suggestions/attribute-typos.rs
index 74f63f2..7c8231b 100644
--- a/src/test/ui/suggestions/attribute-typos.rs
+++ b/src/test/ui/suggestions/attribute-typos.rs
@@ -1,11 +1,11 @@
-#[deprcated] //~ ERROR cannot find attribute macro `deprcated` in this scope
+#[deprcated] //~ ERROR cannot find attribute `deprcated` in this scope
 fn foo() {}
 
-#[tests] //~ ERROR cannot find attribute macro `tests` in this scope
+#[tests] //~ ERROR cannot find attribute `tests` in this scope
 fn bar() {}
 
 #[rustc_err]
-//~^ ERROR cannot find attribute macro `rustc_err` in this scope
+//~^ ERROR cannot find attribute `rustc_err` in this scope
 //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 
 fn main() {}
diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr
index 6b2f591..e403293 100644
--- a/src/test/ui/suggestions/attribute-typos.stderr
+++ b/src/test/ui/suggestions/attribute-typos.stderr
@@ -7,19 +7,19 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error: cannot find attribute macro `rustc_err` in this scope
+error: cannot find attribute `rustc_err` in this scope
   --> $DIR/attribute-typos.rs:7:3
    |
 LL | #[rustc_err]
    |   ^^^^^^^^^ help: a built-in attribute with a similar name exists: `rustc_error`
 
-error: cannot find attribute macro `tests` in this scope
+error: cannot find attribute `tests` in this scope
   --> $DIR/attribute-typos.rs:4:3
    |
 LL | #[tests]
    |   ^^^^^ help: an attribute macro with a similar name exists: `test`
 
-error: cannot find attribute macro `deprcated` in this scope
+error: cannot find attribute `deprcated` in this scope
   --> $DIR/attribute-typos.rs:1:3
    |
 LL | #[deprcated]
diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
index 48c2503..4aec720 100644
--- a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
+++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
@@ -2,7 +2,7 @@
   --> $DIR/impl-trait-with-missing-trait-bounds-in-arg.rs:15:9
    |
 LL |     foo.hello();
-   |         ^^^^^
+   |         ^^^^^ method not found in `impl Foo`
    |
    = help: items from traits can only be used if the type parameter is bounded by the trait
 help: the following trait defines an item `hello`, perhaps you need to restrict type parameter `impl Foo` with it:
diff --git a/src/test/ui/suggestions/issue-21673.stderr b/src/test/ui/suggestions/issue-21673.stderr
index 6cf71c8..f2496f6 100644
--- a/src/test/ui/suggestions/issue-21673.stderr
+++ b/src/test/ui/suggestions/issue-21673.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-21673.rs:6:7
    |
 LL |     x.method()
-   |       ^^^^^^
+   |       ^^^^^^ method not found in `&T`
    |
    = help: items from traits can only be used if the type parameter is bounded by the trait
 help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
@@ -14,7 +14,7 @@
   --> $DIR/issue-21673.rs:10:7
    |
 LL |     x.method()
-   |       ^^^^^^
+   |       ^^^^^^ method not found in `T`
    |
    = help: items from traits can only be used if the type parameter is bounded by the trait
 help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr
index ad4a4de..4678410 100644
--- a/src/test/ui/suggestions/suggest-methods.stderr
+++ b/src/test/ui/suggestions/suggest-methods.stderr
@@ -23,7 +23,7 @@
   --> $DIR/suggest-methods.rs:28:19
    |
 LL |     let _ = 63u32.count_o();
-   |                   ^^^^^^^
+   |                   ^^^^^^^ method not found in `u32`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/syntax-extension-minor.rs b/src/test/ui/syntax-extension-minor.rs
index 0206a76..2d6710a 100644
--- a/src/test/ui/syntax-extension-minor.rs
+++ b/src/test/ui/syntax-extension-minor.rs
@@ -1,3 +1,5 @@
+// run-pass
+
 #![feature(concat_idents)]
 
 pub fn main() {
@@ -5,10 +7,8 @@
     let _: concat_idents!(F, oo) = Foo; // Test that `concat_idents!` can be used in type positions
 
     let asdf_fdsa = "<.<".to_string();
-    // this now fails (correctly, I claim) because hygiene prevents
-    // the assembled identifier from being a reference to the binding.
+    // concat_idents should have call-site hygiene.
     assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
-    //~^ ERROR cannot find value `asdf_fdsa` in this scope
 
     assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction");
 }
diff --git a/src/test/ui/syntax-extension-minor.stderr b/src/test/ui/syntax-extension-minor.stderr
deleted file mode 100644
index 2d8056d..0000000
--- a/src/test/ui/syntax-extension-minor.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `asdf_fdsa` in this scope
-  --> $DIR/syntax-extension-minor.rs:10:13
-   |
-LL |     assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/tool-attributes/diagnostic_item.rs b/src/test/ui/tool-attributes/diagnostic_item.rs
index 1d35422..26a52ce 100644
--- a/src/test/ui/tool-attributes/diagnostic_item.rs
+++ b/src/test/ui/tool-attributes/diagnostic_item.rs
@@ -1,2 +1,3 @@
 #[rustc_diagnostic_item = "foomp"] //~ ERROR compiler internal support for linting
 struct Foomp;
+fn main() {}
diff --git a/src/test/ui/tool-attributes/diagnostic_item.stderr b/src/test/ui/tool-attributes/diagnostic_item.stderr
index deff4da..5432f8d 100644
--- a/src/test/ui/tool-attributes/diagnostic_item.stderr
+++ b/src/test/ui/tool-attributes/diagnostic_item.stderr
@@ -7,11 +7,6 @@
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0601]: `main` function not found in crate `diagnostic_item`
-   |
-   = note: consider adding a `main` function to `$DIR/diagnostic_item.rs`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0601, E0658.
-For more information about an error, try `rustc --explain E0601`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
index 8c62b34..d5698be 100644
--- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
+++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
@@ -4,14 +4,14 @@
 #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
 struct S;
 
-// Interpreted as a feature gated custom attribute
-#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
+// Interpreted as an unstable custom attribute
+#[rustfmt] //~ ERROR cannot find attribute `rustfmt` in this scope
 fn check() {}
 
 #[rustfmt::skip] // OK
 fn main() {
     rustfmt; //~ ERROR expected value, found tool module `rustfmt`
-    rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
+    rustfmt!(); //~ ERROR cannot find macro `rustfmt` in this scope
 
     rustfmt::skip; //~ ERROR expected value, found tool attribute `rustfmt::skip`
 }
diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
index 33581a1..6bef793 100644
--- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
+++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
@@ -4,13 +4,13 @@
 LL | #[derive(rustfmt)]
    |          ^^^^^^^
 
-error: cannot find attribute macro `rustfmt` in this scope
+error: cannot find attribute `rustfmt` in this scope
   --> $DIR/tool-attributes-misplaced-1.rs:8:3
    |
 LL | #[rustfmt]
    |   ^^^^^^^
 
-error: cannot find macro `rustfmt!` in this scope
+error: cannot find macro `rustfmt` in this scope
   --> $DIR/tool-attributes-misplaced-1.rs:14:5
    |
 LL |     rustfmt!();
diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs b/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs
index fb26b7e..1440f02 100644
--- a/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // This test checks that trait objects involving trait aliases are well-formed.
 
diff --git a/src/test/ui/traits/trait-impl-1.stderr b/src/test/ui/traits/trait-impl-1.stderr
index 71d5cc2..0d61c3e 100644
--- a/src/test/ui/traits/trait-impl-1.stderr
+++ b/src/test/ui/traits/trait-impl-1.stderr
@@ -2,7 +2,7 @@
   --> $DIR/trait-impl-1.rs:15:7
    |
 LL |     x.foo();
-   |       ^^^
+   |       ^^^ method not found in `&i32`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr
index 16ea7bd..39cc66d 100644
--- a/src/test/ui/traits/trait-item-privacy.stderr
+++ b/src/test/ui/traits/trait-item-privacy.stderr
@@ -5,7 +5,7 @@
    | --------- method `a` not found for this
 ...
 LL |     S.a();
-   |       ^
+   |       ^ method not found in `S`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `a`, perhaps you need to implement it:
@@ -25,7 +25,7 @@
    |            the method is available for `std::rc::Rc<S>` here
 ...
 LL |     S.b();
-   |       ^
+   |       ^ method not found in `S`
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr
index f0f0481..d172d5e 100644
--- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr
+++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr
@@ -12,7 +12,7 @@
   --> $DIR/trivial-bounds-leak.rs:24:10
    |
 LL |     3i32.test();
-   |          ^^^^
+   |          ^^^^ method not found in `i32`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `test`, perhaps you need to implement it:
diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs
index 0c21209..19fcc78 100644
--- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs
+++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs
@@ -9,13 +9,13 @@
 
 #![allow(irrefutable_let_patterns)]
 
-enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+enum Enum<T> { TSVariant(T), SVariant { _v: T }, UVariant }
 type Alias<T> = Enum<T>;
 type AliasFixed = Enum<()>;
 
 macro_rules! is_variant {
     (TSVariant, $expr:expr) => (is_variant!(@check TSVariant, (_), $expr));
-    (SVariant, $expr:expr) => (is_variant!(@check SVariant, { v: _ }, $expr));
+    (SVariant, $expr:expr) => (is_variant!(@check SVariant, { _v: _ }, $expr));
     (UVariant, $expr:expr) => (is_variant!(@check UVariant, {}, $expr));
     (@check $variant:ident, $matcher:tt, $expr:expr) => (
         assert!(if let Enum::$variant::<()> $matcher = $expr { true } else { false },
@@ -37,14 +37,14 @@
 
     // Struct variant
 
-    is_variant!(SVariant, Enum::SVariant { v: () });
-    is_variant!(SVariant, Enum::SVariant::<()> { v: () });
-    is_variant!(SVariant, Enum::<()>::SVariant { v: () });
+    is_variant!(SVariant, Enum::SVariant { _v: () });
+    is_variant!(SVariant, Enum::SVariant::<()> { _v: () });
+    is_variant!(SVariant, Enum::<()>::SVariant { _v: () });
 
-    is_variant!(SVariant, Alias::SVariant { v: () });
-    is_variant!(SVariant, Alias::<()>::SVariant { v: () });
+    is_variant!(SVariant, Alias::SVariant { _v: () });
+    is_variant!(SVariant, Alias::<()>::SVariant { _v: () });
 
-    is_variant!(SVariant, AliasFixed::SVariant { v: () });
+    is_variant!(SVariant, AliasFixed::SVariant { _v: () });
 
     // Unit variant
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs
index 91c4576..9e96b1c 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs
@@ -24,3 +24,5 @@
             .map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
     }
 }
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
index ebb13fc..b838c06 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
@@ -1,7 +1,3 @@
-error[E0601]: `main` function not found in crate `issue_60564`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-60564.rs`
-
 error: type parameter `E` is part of concrete type but not used in parameter list for the `impl Trait` type alias
   --> $DIR/issue-60564.rs:20:49
    |
@@ -20,6 +16,5 @@
 LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/type/ascription/issue-34255-1.rs b/src/test/ui/type/ascription/issue-34255-1.rs
index c11a248..c21d9f3 100644
--- a/src/test/ui/type/ascription/issue-34255-1.rs
+++ b/src/test/ui/type/ascription/issue-34255-1.rs
@@ -13,3 +13,4 @@
 }
 
 // This case isn't currently being handled gracefully, including for completeness.
+fn main() {}
diff --git a/src/test/ui/type/ascription/issue-34255-1.stderr b/src/test/ui/type/ascription/issue-34255-1.stderr
index 531455b..195b393 100644
--- a/src/test/ui/type/ascription/issue-34255-1.stderr
+++ b/src/test/ui/type/ascription/issue-34255-1.stderr
@@ -14,17 +14,13 @@
    = 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 #42238 <https://github.com/rust-lang/rust/issues/42238>
 
-error[E0601]: `main` function not found in crate `issue_34255_1`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-34255-1.rs`
-
 error[E0107]: wrong number of type arguments: expected 1, found 0
   --> $DIR/issue-34255-1.rs:7:22
    |
 LL |         input_cells: Vec::new()
    |                      ^^^^^^^^^^ expected 1 type argument
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0107, E0425, E0601.
+Some errors have detailed explanations: E0107, E0425.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/type/ascription/issue-54516.rs b/src/test/ui/type/ascription/issue-54516.rs
index 6d65760..b53bfe5 100644
--- a/src/test/ui/type/ascription/issue-54516.rs
+++ b/src/test/ui/type/ascription/issue-54516.rs
@@ -2,5 +2,5 @@
 
 fn main() {
     println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
-    //~^ ERROR expected token: `,`
+    //~^ ERROR expected one of
 }
diff --git a/src/test/ui/type/ascription/issue-54516.stderr b/src/test/ui/type/ascription/issue-54516.stderr
index a846f3b..9794290 100644
--- a/src/test/ui/type/ascription/issue-54516.stderr
+++ b/src/test/ui/type/ascription/issue-54516.stderr
@@ -1,8 +1,8 @@
-error: expected token: `,`
+error: expected one of `!`, `,`, or `::`, found `(`
   --> $DIR/issue-54516.rs:4:58
    |
 LL |     println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
-   |                            -                             ^ expected `,`
+   |                            -                             ^ expected one of `!`, `,`, or `::` here
    |                            |
    |                            help: maybe write a path separator here: `::`
    |
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
index 2e18458..18276d5 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
@@ -2,7 +2,7 @@
   --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
    |
 LL |     mut_.call((0, ));
-   |          ^^^^
+   |          ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
    |
    = note: mut_ is a function, perhaps you wish to call it
 
diff --git a/src/test/ui/underscore-imports/shadow.stderr b/src/test/ui/underscore-imports/shadow.stderr
index 92adca2..63262d0 100644
--- a/src/test/ui/underscore-imports/shadow.stderr
+++ b/src/test/ui/underscore-imports/shadow.stderr
@@ -2,7 +2,7 @@
   --> $DIR/shadow.rs:19:11
    |
 LL |         x.deref();
-   |           ^^^^^
+   |           ^^^^^ method not found in `&()`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
index 45976f8..29ff1dc 100644
--- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
+++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
@@ -3,6 +3,7 @@
    |
 LL | / enum Foo {
 LL | |     A(foo::SecretlyEmpty),
+   | |     - not covered
 LL | |     B(foo::NotSoSecretlyEmpty),
 LL | |     C(NotSoSecretlyEmpty),
 LL | |     D(u32),
diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr
index 37a0093..4f4c779 100644
--- a/src/test/ui/union/union-derive-clone.stderr
+++ b/src/test/ui/union/union-derive-clone.stderr
@@ -13,7 +13,7 @@
    | ----------- method `clone` not found for this
 ...
 LL |     let w = u.clone();
-   |               ^^^^^
+   |               ^^^^^ method not found in `U4<CloneNoCopy>`
    |
    = note: the method `clone` exists but the following trait bounds were not satisfied:
            `U4<CloneNoCopy> : std::clone::Clone`
diff --git a/src/test/ui/union/union-repr-c.rs b/src/test/ui/union/union-repr-c.rs
index 658452d..1367835 100644
--- a/src/test/ui/union/union-repr-c.rs
+++ b/src/test/ui/union/union-repr-c.rs
@@ -12,7 +12,7 @@
 
 extern "C" {
     static FOREIGN1: U; // OK
-    static FOREIGN2: W; //~ ERROR union has unspecified layout
+    static FOREIGN2: W; //~ ERROR `extern` block uses type `W`
 }
 
 fn main() {}
diff --git a/src/test/ui/union/union-repr-c.stderr b/src/test/ui/union/union-repr-c.stderr
index c60817a..c8bc038 100644
--- a/src/test/ui/union/union-repr-c.stderr
+++ b/src/test/ui/union/union-repr-c.stderr
@@ -1,8 +1,8 @@
-error: `extern` block uses type `W` which is not FFI-safe: this union has unspecified layout
+error: `extern` block uses type `W`, which is not FFI-safe
   --> $DIR/union-repr-c.rs:15:22
    |
 LL |     static FOREIGN2: W;
-   |                      ^
+   |                      ^ not FFI-safe
    |
 note: lint level defined here
   --> $DIR/union-repr-c.rs:2:9
@@ -10,6 +10,7 @@
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+   = note: this union has unspecified layout
 note: type defined here
   --> $DIR/union-repr-c.rs:9:1
    |
diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr
index 407905f..cd46878 100644
--- a/src/test/ui/unique-object-noncopyable.stderr
+++ b/src/test/ui/unique-object-noncopyable.stderr
@@ -2,7 +2,7 @@
   --> $DIR/unique-object-noncopyable.rs:24:16
    |
 LL |     let _z = y.clone();
-   |                ^^^^^
+   |                ^^^^^ method not found in `std::boxed::Box<dyn Foo>`
    |
    = note: the method `clone` exists but the following trait bounds were not satisfied:
            `std::boxed::Box<dyn Foo> : std::clone::Clone`
diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr
index 0f6ba90..19ef2b2 100644
--- a/src/test/ui/unique-pinned-nocopy.stderr
+++ b/src/test/ui/unique-pinned-nocopy.stderr
@@ -2,7 +2,7 @@
   --> $DIR/unique-pinned-nocopy.rs:12:16
    |
 LL |     let _j = i.clone();
-   |                ^^^^^
+   |                ^^^^^ method not found in `std::boxed::Box<R>`
    |
    = note: the method `clone` exists but the following trait bounds were not satisfied:
            `std::boxed::Box<R> : std::clone::Clone`
diff --git a/src/test/ui/while-let.rs b/src/test/ui/while-let.rs
index 69f9de9..53babef 100644
--- a/src/test/ui/while-let.rs
+++ b/src/test/ui/while-let.rs
@@ -1,5 +1,6 @@
 // run-pass
 
+#[allow(dead_code)]
 fn macros() {
     macro_rules! foo{
         ($p:pat, $e:expr, $b:block) => {{
@@ -12,16 +13,16 @@
         }}
     }
 
-    foo!(a, 1, { //~ WARN irrefutable while-let
+    foo!(_a, 1, { //~ WARN irrefutable while-let
         println!("irrefutable pattern");
     });
-    bar!(a, 1, { //~ WARN irrefutable while-let
+    bar!(_a, 1, { //~ WARN irrefutable while-let
         println!("irrefutable pattern");
     });
 }
 
 pub fn main() {
-    while let a = 1 { //~ WARN irrefutable while-let
+    while let _a = 1 { //~ WARN irrefutable while-let
         println!("irrefutable pattern");
         break;
     }
diff --git a/src/test/ui/while-let.stderr b/src/test/ui/while-let.stderr
index 348925a..30307ec 100644
--- a/src/test/ui/while-let.stderr
+++ b/src/test/ui/while-let.stderr
@@ -1,10 +1,10 @@
 warning: irrefutable while-let pattern
-  --> $DIR/while-let.rs:6:13
+  --> $DIR/while-let.rs:7:13
    |
 LL |               while let $p = $e $b
    |               ^^^^^
 ...
-LL | /     foo!(a, 1, {
+LL | /     foo!(_a, 1, {
 LL | |         println!("irrefutable pattern");
 LL | |     });
    | |_______- in this macro invocation
@@ -12,20 +12,20 @@
    = note: `#[warn(irrefutable_let_patterns)]` on by default
 
 warning: irrefutable while-let pattern
-  --> $DIR/while-let.rs:6:13
+  --> $DIR/while-let.rs:7:13
    |
 LL |               while let $p = $e $b
    |               ^^^^^
 ...
-LL | /     bar!(a, 1, {
+LL | /     bar!(_a, 1, {
 LL | |         println!("irrefutable pattern");
 LL | |     });
    | |_______- in this macro invocation
 
 warning: irrefutable while-let pattern
-  --> $DIR/while-let.rs:24:5
+  --> $DIR/while-let.rs:25:5
    |
-LL | /     while let a = 1 {
+LL | /     while let _a = 1 {
 LL | |         println!("irrefutable pattern");
 LL | |         break;
 LL | |     }
diff --git a/src/tools/cargo b/src/tools/cargo
index fe0e5a4..9655d70 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit fe0e5a48b75da2b405c8ce1ba2674e174ae11d5d
+Subproject commit 9655d70af8a6dddac238e3afa2fec75088c9226f
diff --git a/src/tools/clippy b/src/tools/clippy
index 5f28fda..58e01ea 160000
--- a/src/tools/clippy
+++ b/src/tools/clippy
@@ -1 +1 @@
-Subproject commit 5f28fda13efeb85097fe082af4b4827a58b0ecf6
+Subproject commit 58e01ea4d7df69e658c034afbfa6d0abd90808ed
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 819d399..48dd68d 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -628,6 +628,11 @@
         }
         self.pass_mode
     }
+
+    // does not consider CLI override for pass mode
+    pub fn local_pass_mode(&self) -> Option<PassMode> {
+        self.pass_mode
+    }
 }
 
 fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 467b777..7c51de5 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -253,7 +253,7 @@
     if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
         let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
         println!("{}", opts.usage(&message));
-        println!("");
+        println!();
         panic!()
     }
 
@@ -265,7 +265,7 @@
     if matches.opt_present("h") || matches.opt_present("help") {
         let message = format!("Usage: {} [OPTIONS]  [TESTNAME...]", argv0);
         println!("{}", opts.usage(&message));
-        println!("");
+        println!();
         panic!()
     }
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 9a3d24f..baed27d 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1557,7 +1557,11 @@
                 // want to actually assert warnings about all this code. Instead
                 // let's just ignore unused code warnings by defaults and tests
                 // can turn it back on if needed.
-                if !self.config.src_base.ends_with("rustdoc-ui") {
+                if !self.config.src_base.ends_with("rustdoc-ui") &&
+                    // Note that we don't call pass_mode() here as we don't want
+                    // to set unused to allow if we've overriden the pass mode
+                    // via command line flags.
+                    self.props.local_pass_mode() != Some(PassMode::Run) {
                     rustc.args(&["-A", "unused"]);
                 }
             }
@@ -2589,7 +2593,7 @@
                     "  actual:   {}",
                     codegen_units_to_str(&actual_item.codegen_units)
                 );
-                println!("");
+                println!();
             }
         }
 
@@ -3522,7 +3526,7 @@
                             }
                         }
                     }
-                    println!("");
+                    println!();
                 }
             }
         }
diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs
index 832aa3b..592b3f1 100644
--- a/src/tools/error_index_generator/build.rs
+++ b/src/tools/error_index_generator/build.rs
@@ -35,7 +35,7 @@
         ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
             $(
                 {long_codes.extend([
-                    (stringify!($ecode), Some(stringify!($message))),
+                    (stringify!($ecode), Some($message)),
                 ].iter());}
             )*
             $(
diff --git a/src/tools/miri b/src/tools/miri
index e479ab2..d881387 160000
--- a/src/tools/miri
+++ b/src/tools/miri
@@ -1 +1 @@
-Subproject commit e479ab26406ed8a473987e5f4a1f3be3e978e5d2
+Subproject commit d88138723780d11ca2c09560111223dc20b9d5f3
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 1411f4c..4060b90 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -7,6 +7,8 @@
 ## It is set as callback for `src/ci/docker/x86_64-gnu-tools/repo.sh` by the CI scripts
 ## when a new commit lands on `master` (i.e., after it passed all checks on `auto`).
 
+from __future__ import print_function
+
 import sys
 import re
 import os
@@ -20,21 +22,26 @@
     import urllib.request as urllib2
 
 # List of people to ping when the status of a tool or a book changed.
+# These should be collaborators of the rust-lang/rust repository (with at least
+# read privileges on it). CI will fail otherwise.
 MAINTAINERS = {
-    'miri': '@oli-obk @RalfJung @eddyb',
-    'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch @flip1995',
-    'rls': '@Xanewok',
-    'rustfmt': '@topecongiro',
-    'book': '@carols10cents @steveklabnik',
-    'nomicon': '@frewsxcv @Gankro',
-    'reference': '@steveklabnik @Havvy @matthewjasper @ehuss',
-    'rust-by-example': '@steveklabnik @marioidival @projektir',
-    'embedded-book': (
-        '@adamgreig @andre-richter @jamesmunns @korken89 '
-        '@ryankurte @thejpster @therealprof'
-    ),
-    'edition-guide': '@ehuss @Centril @steveklabnik',
-    'rustc-guide': '@mark-i-m @spastorino @amanjeev'
+    'miri': {'oli-obk', 'RalfJung', 'eddyb'},
+    'clippy-driver': {
+        'Manishearth', 'llogiq', 'mcarton', 'oli-obk', 'phansch', 'flip1995',
+        'yaahc',
+    },
+    'rls': {'Xanewok'},
+    'rustfmt': {'topecongiro'},
+    'book': {'carols10cents', 'steveklabnik'},
+    'nomicon': {'frewsxcv', 'Gankra'},
+    'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'},
+    'rust-by-example': {'steveklabnik', 'marioidival'},
+    'embedded-book': {
+        'adamgreig', 'andre-richter', 'jamesmunns', 'korken89',
+        'ryankurte', 'thejpster', 'therealprof',
+    },
+    'edition-guide': {'ehuss', 'Centril', 'steveklabnik'},
+    'rustc-guide': {'mark-i-m', 'spastorino', 'amanjeev'},
 }
 
 REPOS = {
@@ -52,6 +59,50 @@
 }
 
 
+def validate_maintainers(repo, github_token):
+    '''Ensure all maintainers are assignable on a GitHub repo'''
+    next_link_re = re.compile(r'<([^>]+)>; rel="next"')
+
+    # Load the list of assignable people in the GitHub repo
+    assignable = []
+    url = 'https://api.github.com/repos/%s/collaborators?per_page=100' % repo
+    while url is not None:
+        response = urllib2.urlopen(urllib2.Request(url, headers={
+            'Authorization': 'token ' + github_token,
+            # Properly load nested teams.
+            'Accept': 'application/vnd.github.hellcat-preview+json',
+        }))
+        assignable.extend(user['login'] for user in json.load(response))
+        # Load the next page if available
+        url = None
+        link_header = response.headers.get('Link')
+        if link_header:
+            matches = next_link_re.match(link_header)
+            if matches is not None:
+                url = matches.group(1)
+
+    errors = False
+    for tool, maintainers in MAINTAINERS.items():
+        for maintainer in maintainers:
+            if maintainer not in assignable:
+                errors = True
+                print(
+                    "error: %s maintainer @%s is not assignable in the %s repo"
+                    % (tool, maintainer, repo),
+                )
+
+    if errors:
+        print()
+        print("  To be assignable, a person needs to be explicitly listed as a")
+        print("  collaborator in the repository settings. The simple way to")
+        print("  fix this is to ask someone with 'admin' privileges on the repo")
+        print("  to add the person or whole team as a collaborator with 'read'")
+        print("  privileges. Those privileges don't grant any extra permissions")
+        print("  so it's safe to apply them.")
+        print()
+        print("The build will fail due to this.")
+        exit(1)
+
 def read_current_status(current_commit, path):
     '''Reads build status of `current_commit` from content of `history/*.tsv`
     '''
@@ -73,13 +124,12 @@
 def issue(
     tool,
     status,
-    maintainers,
+    assignees,
     relevant_pr_number,
     relevant_pr_user,
     pr_reviewer,
 ):
     # Open an issue about the toolstate failure.
-    assignees = [x.strip() for x in maintainers.split('@') if x != '']
     if status == 'test-fail':
         status_description = 'has failing tests'
     else:
@@ -100,7 +150,7 @@
             REPOS.get(tool), relevant_pr_user, pr_reviewer
         )),
         'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number),
-        'assignees': assignees,
+        'assignees': list(assignees),
         'labels': ['T-compiler', 'I-nominated'],
     })
     print("Creating issue:\n{}".format(request))
@@ -150,18 +200,19 @@
                 old = status[os]
                 new = s.get(tool, old)
                 status[os] = new
+                maintainers = ' '.join('@'+name for name in MAINTAINERS[tool])
                 if new > old: # comparing the strings, but they are ordered appropriately!
                     # things got fixed or at least the status quo improved
                     changed = True
                     message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \
-                        .format(tool, os, old, new, MAINTAINERS.get(tool))
+                        .format(tool, os, old, new, maintainers)
                 elif new < old:
                     # tests or builds are failing and were not failing before
                     changed = True
                     title = '💔 {} on {}: {} → {}' \
                         .format(tool, os, old, new)
                     message += '{} (cc {}, @rust-lang/infra).\n' \
-                        .format(title, MAINTAINERS.get(tool))
+                        .format(title, maintainers)
                     # Most tools only create issues for build failures.
                     # Other failures can be spurious.
                     if new == 'build-fail' or (tool == 'miri' and new == 'test-fail'):
@@ -200,6 +251,16 @@
 
 
 if __name__ == '__main__':
+    repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO')
+    if repo:
+        github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN')
+        if github_token:
+            validate_maintainers(repo, github_token)
+        else:
+            print('skipping toolstate maintainers validation since no GitHub token is present')
+        # When validating maintainers don't run the full script.
+        exit(0)
+
     cur_commit = sys.argv[1]
     cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
     cur_commit_msg = sys.argv[2]
diff --git a/src/tools/rls b/src/tools/rls
index 496c892..d9aa23a 160000
--- a/src/tools/rls
+++ b/src/tools/rls
@@ -1 +1 @@
-Subproject commit 496c89275221303a4b0c2779cb8203fb3ce2a136
+Subproject commit d9aa23a43ad29e3a10551a1425ef5d5baef28d70
diff --git a/src/tools/rustc-std-workspace-alloc/Cargo.toml b/src/tools/rustc-std-workspace-alloc/Cargo.toml
index ef7dc81..9e04b14 100644
--- a/src/tools/rustc-std-workspace-alloc/Cargo.toml
+++ b/src/tools/rustc-std-workspace-alloc/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rustc-std-workspace-alloc"
-version = "1.0.0"
+version = "1.99.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 license = 'MIT OR Apache-2.0'
 description = """
diff --git a/src/tools/rustc-std-workspace-core/Cargo.toml b/src/tools/rustc-std-workspace-core/Cargo.toml
index 38ca56a..6b4e754 100644
--- a/src/tools/rustc-std-workspace-core/Cargo.toml
+++ b/src/tools/rustc-std-workspace-core/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rustc-std-workspace-core"
-version = "1.0.0"
+version = "1.99.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 license = 'MIT OR Apache-2.0'
 description = """
diff --git a/src/tools/rustc-std-workspace-std/Cargo.toml b/src/tools/rustc-std-workspace-std/Cargo.toml
index ce16448..e41554b 100644
--- a/src/tools/rustc-std-workspace-std/Cargo.toml
+++ b/src/tools/rustc-std-workspace-std/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rustc-std-workspace-std"
-version = "1.0.0"
+version = "1.99.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 license = 'MIT OR Apache-2.0'
 description = """
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index 4ce4112..930279c 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -14,12 +14,6 @@
 # For documentation about what this is and why in the world these dependencies
 # are appearing, see `README.md`.
 
-[build-dependencies]
-# Currently Cargo/RLS depend on `failure` which depends on `synstructure` which
-# enables this feature. Clippy, however, does not depend on anything that
-# enables this feature. Enable it unconditionally.
-syn = { version = "0.15", features = ['extra-traits'] }
-
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
 features = [
@@ -65,14 +59,9 @@
 [dependencies]
 curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
 crossbeam-utils = { version = "0.6.5", features = ["nightly"] }
-parking_lot = { version = "0.7", features = ['nightly'] }
-rand = { version = "0.6.1", features = ["i128_support"] }
 serde = { version = "1.0.82", features = ['derive'] }
 serde_json = { version = "1.0.31", features = ["raw_value"] }
 smallvec = { version = "0.6", features = ['union', 'may_dangle'] }
-scopeguard = { version = "0.3.3", features = ["use_std", "default"] }
-byteorder = { version = "1.2.7", features = ["i128"] }
-syn = { version = "0.15.35", features = ["extra-traits", "full"] }
 
 
 [target.'cfg(not(windows))'.dependencies]
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
index f800ce4..afb1ee1 160000
--- a/src/tools/rustfmt
+++ b/src/tools/rustfmt
@@ -1 +1 @@
-Subproject commit f800ce47d1da2a1c02ffd260deca8b7445f7facf
+Subproject commit afb1ee1c14594aed5bb4a762b357b01f13c9de10