about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorkenta7777 <k.hasegw7@gmail.com>2018-09-12 21:36:31 +0900
committerkenta7777 <k.hasegw7@gmail.com>2018-09-12 21:36:31 +0900
commit26dbf56196ccd50a335f38755ea7546f6f1399bd (patch)
tree6c099ff00be225c42e653384ca198cf457879cef /src
parent8134ee25b88df98c79792d60cbf6745b6cb7ffc5 (diff)
parent8586ec6980462c99a8926646201b2444d8938d29 (diff)
downloadrust-26dbf56196ccd50a335f38755ea7546f6f1399bd.tar.gz
rust-26dbf56196ccd50a335f38755ea7546f6f1399bd.zip
Merge branch 'master' into kenta7777#53719
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/README.md18
-rw-r--r--src/doc/rustc/src/lints/index.md2
-rw-r--r--src/doc/rustc/src/lints/levels.md15
-rw-r--r--src/doc/unstable-book/src/language-features/used.md157
-rw-r--r--src/libcore/num/mod.rs3
-rw-r--r--src/libcore/result.rs30
-rw-r--r--src/libproc_macro/lib.rs7
-rw-r--r--src/librustc/hir/map/def_collector.rs57
-rw-r--r--src/librustc/ich/impls_mir.rs6
-rw-r--r--src/librustc/infer/mod.rs731
-rw-r--r--src/librustc/lint/context.rs7
-rw-r--r--src/librustc/lint/mod.rs2
-rw-r--r--src/librustc/mir/mod.rs38
-rw-r--r--src/librustc/mir/visit.rs35
-rw-r--r--src/librustc/ty/context.rs4
-rw-r--r--src/librustc/ty/structural_impls.rs1
-rw-r--r--src/librustc/ty/subst.rs14
-rw-r--r--src/librustc_codegen_llvm/attributes.rs11
-rw-r--r--src/librustc_codegen_llvm/builder.rs8
-rw-r--r--src/librustc_codegen_llvm/callee.rs2
-rw-r--r--src/librustc_codegen_llvm/mir/statement.rs2
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs2
-rw-r--r--src/librustc_lint/lib.rs2
-rw-r--r--src/librustc_llvm/build.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs7
-rw-r--r--src/librustc_mir/borrow_check/nll/invalidation.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs58
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs94
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs348
-rw-r--r--src/librustc_mir/build/block.rs14
-rw-r--r--src/librustc_mir/build/expr/into.rs1
-rw-r--r--src/librustc_mir/build/matches/mod.rs863
-rw-r--r--src/librustc_mir/build/matches/simplify.rs14
-rw-r--r--src/librustc_mir/build/matches/test.rs9
-rw-r--r--src/librustc_mir/build/mod.rs1
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs2
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs2
-rw-r--r--src/librustc_mir/hair/cx/block.rs18
-rw-r--r--src/librustc_mir/hair/mod.rs7
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs136
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs27
-rw-r--r--src/librustc_mir/interpret/step.rs2
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/shim.rs4
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs2
-rw-r--r--src/librustc_mir/transform/cleanup_post_borrowck.rs20
-rw-r--r--src/librustc_mir/transform/generator.rs3
-rw-r--r--src/librustc_mir/transform/mod.rs4
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs2
-rw-r--r--src/librustc_mir/transform/remove_noop_landing_pads.rs2
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs2
-rw-r--r--src/librustc_mir/util/pretty.rs9
-rw-r--r--src/librustc_passes/ast_validation.rs104
-rw-r--r--src/librustc_passes/hir_stats.rs24
-rw-r--r--src/librustc_passes/loops.rs16
-rw-r--r--src/librustc_passes/mir_stats.rs43
-rw-r--r--src/librustc_passes/rvalue_promotion.rs90
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs32
-rw-r--r--src/librustc_resolve/lib.rs66
-rw-r--r--src/librustc_resolve/macros.rs189
-rw-r--r--src/librustc_resolve/resolve_imports.rs145
-rw-r--r--src/librustc_target/abi/call/amdgpu.rs42
-rw-r--r--src/librustc_target/abi/call/mod.rs2
-rw-r--r--src/librustdoc/html/render.rs26
-rw-r--r--src/libstd/collections/hash/map.rs8
-rw-r--r--src/libstd/ffi/c_str.rs5
-rw-r--r--src/libstd/io/mod.rs3
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libsyntax/ext/base.rs11
-rw-r--r--src/libsyntax/ext/expand.rs31
-rw-r--r--src/libsyntax/feature_gate.rs47
-rw-r--r--src/libsyntax/parse/lexer/mod.rs6
-rw-r--r--src/libsyntax/parse/lexer/tokentrees.rs43
-rw-r--r--src/libsyntax_ext/lib.rs14
m---------src/llvm0
-rw-r--r--src/rustllvm/llvm-rebuild-trigger2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs3
-rw-r--r--src/test/incremental/hashes/let_expressions.rs2
-rw-r--r--src/test/mir-opt/basic_assignment.rs81
-rw-r--r--src/test/mir-opt/nll/reborrow-basic.rs38
-rw-r--r--src/test/run-make-fulldeps/used/used.rs1
-rw-r--r--src/test/run-pass/.gitattributes1
-rw-r--r--src/test/run-pass/async-await.rs53
-rw-r--r--src/test/rustdoc/auxiliary/issue-53689.rs (renamed from src/test/ui/feature-gates/feature-gate-used.rs)8
-rw-r--r--src/test/rustdoc/issue-53689.rs26
-rw-r--r--src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs20
-rw-r--r--src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr9
-rw-r--r--src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs31
-rw-r--r--src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr100
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs36
-rw-r--r--src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs22
-rw-r--r--src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr20
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr22
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr13
-rw-r--r--src/test/ui/directory_ownership/mod_file_not_owning.stderr15
-rw-r--r--src/test/ui/directory_ownership/unowned_mod_with_path.stderr15
-rw-r--r--src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr16
-rw-r--r--src/test/ui/feature-gate/issue-43106-gating-of-bench.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-linker-flavor.rs3
-rw-r--r--src/test/ui/feature-gates/feature-gate-linker-flavor.stderr5
-rw-r--r--src/test/ui/feature-gates/feature-gate-used.stderr11
-rw-r--r--src/test/ui/issue-53565.rs14
-rw-r--r--src/test/ui/issue-53565.stderr20
-rw-r--r--src/test/ui/issues/issue-11692-2.rs3
-rw-r--r--src/test/ui/issues/issue-11692-2.stderr4
-rw-r--r--src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs11
-rw-r--r--src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr8
-rw-r--r--src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs5
-rw-r--r--src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr8
-rw-r--r--src/test/ui/nll/relate_tys/universe-violation.rs17
-rw-r--r--src/test/ui/nll/relate_tys/universe-violation.stderr8
-rw-r--r--src/test/ui/nll/relate_tys/var-appears-twice.rs38
-rw-r--r--src/test/ui/nll/relate_tys/var-appears-twice.stderr14
-rw-r--r--src/test/ui/nll/user-annotations/patterns.rs121
-rw-r--r--src/test/ui/nll/user-annotations/patterns.stderr143
-rw-r--r--src/test/ui/non_modrs_mods/non_modrs_mods.rs28
-rw-r--r--src/test/ui/non_modrs_mods/non_modrs_mods.stderr39
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs49
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr56
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs49
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr56
-rw-r--r--src/test/ui/run-pass/issues/.gitattributes1
-rw-r--r--src/test/ui/run-pass/issues/issue-16278.rs5
-rw-r--r--src/test/ui/run-pass/issues/issue-41628.rs1
-rw-r--r--src/test/ui/run-pass/non_modrs_mods/non_modrs_mods.rs28
-rw-r--r--src/test/ui/rust-2018/async-ident.fixed4
-rw-r--r--src/test/ui/rust-2018/async-ident.rs2
-rw-r--r--src/test/ui/rust-2018/async-ident.stderr33
-rw-r--r--src/test/ui/rust-2018/try-macro.fixed16
-rw-r--r--src/test/ui/rust-2018/try-macro.rs16
-rw-r--r--src/test/ui/rust-2018/try-macro.stderr15
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs29
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr16
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs27
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr16
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs24
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr16
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs (renamed from src/test/ui/directory_ownership/mod_file_not_owning.rs)11
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr16
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs (renamed from src/test/ui/directory_ownership/unowned_mod_with_path.rs)16
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr31
-rw-r--r--src/test/ui/rust-2018/uniform-paths-forward-compat/redundant.rs30
-rw-r--r--src/test/ui/rust-2018/uniform-paths/redundant.rs (renamed from src/test/run-pass/redundant.rs)3
-rw-r--r--src/test/ui/span/issue-36530.rs3
-rw-r--r--src/test/ui/span/issue-36530.stderr14
-rw-r--r--src/test/ui/test-shadowing/test-cant-be-shadowed.rs5
-rw-r--r--src/test/ui/try-block/try-block-bad-lifetime.stderr5
-rw-r--r--src/test/ui/used.rs2
-rw-r--r--src/test/ui/used.stderr8
m---------src/tools/cargo0
m---------src/tools/rls0
156 files changed, 3525 insertions, 1896 deletions
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index 98c353eb6ec..1e01d68fb3a 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -8,14 +8,14 @@ system.
 
 The rustbuild build system has a primary entry point, a top level `x.py` script:
 
-```
-python ./x.py build
+```sh
+$ python ./x.py build
 ```
 
 Note that if you're on Unix you should be able to execute the script directly:
 
-```
-./x.py build
+```sh
+$ ./x.py build
 ```
 
 The script accepts commands, flags, and arguments to determine what to do:
@@ -129,18 +129,18 @@ To follow this course of action, first thing you will want to do is to
 install a nightly, presumably using `rustup`. You will then want to
 configure your directory to use this build, like so:
 
-```
+```sh
 # configure to use local rust instead of downloading a beta.
 # `--local-rust-root` is optional here. If elided, we will
 # use whatever rustc we find on your PATH.
-> ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
+$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
 ```
 
 After that, you can use the `--incremental` flag to actually do
 incremental builds:
 
-```
-> ./x.py build --incremental
+```sh
+$ ./x.py build --incremental
 ```
 
 The `--incremental` flag will store incremental compilation artifacts
@@ -159,7 +159,7 @@ will still be using the local nightly as your bootstrap).
 This build system houses all output under the `build` directory, which looks
 like this:
 
-```
+```sh
 # Root folder of all output. Everything is scoped underneath here
 build/
 
diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md
index bf345a24389..49c0026ce1a 100644
--- a/src/doc/rustc/src/lints/index.md
+++ b/src/doc/rustc/src/lints/index.md
@@ -12,7 +12,7 @@ $ cat main.rs
 fn main() {
     let x = 5;
 }
-> rustc main.rs
+$ rustc main.rs
 warning: unused variable: `x`
  --> main.rs:2:9
   |
diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md
index 19bb6707d22..072c7585934 100644
--- a/src/doc/rustc/src/lints/levels.md
+++ b/src/doc/rustc/src/lints/levels.md
@@ -45,7 +45,7 @@ pub fn foo() {
 
 This will produce this warning:
 
-```console
+```bash
 $ rustc lib.rs --crate-type=lib
 warning: unused variable: `x`
  --> lib.rs:2:9
@@ -69,7 +69,7 @@ fn main() {
 ```
 
 ```bash
-> rustc main.rs
+$ rustc main.rs
 error: bitshift exceeds the type's number of bits
  --> main.rs:2:13
   |
@@ -129,7 +129,10 @@ warning: missing documentation for a function
   |
 1 | pub fn foo() {}
   | ^^^^^^^^^^^^
-> rustc lib.rs --crate-type=lib -D missing-docs
+```
+
+```bash
+$ rustc lib.rs --crate-type=lib -D missing-docs
 error: missing documentation for crate
  --> lib.rs:1:1
   |
@@ -150,13 +153,13 @@ error: aborting due to 2 previous errors
 You can also pass each flag more than once for changing multiple lints:
 
 ```bash
-rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables
+$ rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables
 ```
 
 And of course, you can mix these four flags together:
 
 ```bash
-rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables
+$ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables
 ```
 
 ### Via an attribute
@@ -164,7 +167,7 @@ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables
 You can also modify the lint level with a crate-wide attribute:
 
 ```bash
-> cat lib.rs
+$ cat lib.rs
 #![warn(missing_docs)]
 
 pub fn foo() {}
diff --git a/src/doc/unstable-book/src/language-features/used.md b/src/doc/unstable-book/src/language-features/used.md
deleted file mode 100644
index d49271382b6..00000000000
--- a/src/doc/unstable-book/src/language-features/used.md
+++ /dev/null
@@ -1,157 +0,0 @@
-# `used`
-
-The tracking issue for this feature
-is: [40289](https://github.com/rust-lang/rust/issues/40289).
-
-------------------------
-
-The `#[used]` attribute can be applied to `static` variables to prevent the Rust
-compiler from optimizing them away even if they appear to be unused by the crate
-(appear to be "dead code").
-
-``` rust
-#![feature(used)]
-
-#[used]
-static FOO: i32 = 1;
-
-static BAR: i32 = 2;
-
-fn main() {}
-```
-
-If you compile this program into an object file, you'll see that `FOO` makes it
-to the object file but `BAR` doesn't. Neither static variable is used by the
-program.
-
-``` text
-$ rustc -C opt-level=3 --emit=obj used.rs
-
-$ nm -C used.o
-0000000000000000 T main
-                 U std::rt::lang_start
-0000000000000000 r used::FOO
-0000000000000000 t used::main
-```
-
-Note that the *linker* knows nothing about the `#[used]` attribute and will
-remove `#[used]` symbols if they are not referenced by other parts of the
-program:
-
-``` text
-$ rustc -C opt-level=3 used.rs
-
-$ nm -C used | grep FOO
-```
-
-"This doesn't sound too useful then!" you may think but keep reading.
-
-To preserve the symbols all the way to the final binary, you'll need the
-cooperation of the linker. Here's one example:
-
-The ELF standard defines two special sections, `.init_array` and
-`.pre_init_array`, that may contain function pointers which will be executed
-*before* the `main` function is invoked. The linker will preserve symbols placed
-in these sections (at least when linking programs that target the `*-*-linux-*`
-targets).
-
-``` rust,ignore
-#![feature(used)]
-
-extern "C" fn before_main() {
-    println!("Hello, world!");
-}
-
-#[link_section = ".init_array"]
-#[used]
-static INIT_ARRAY: [extern "C" fn(); 1] = [before_main];
-
-fn main() {}
-```
-
-So, `#[used]` and `#[link_section]` can be combined to obtain "life before
-main".
-
-``` text
-$ rustc -C opt-level=3 before-main.rs
-
-$ ./before-main
-Hello, world!
-```
-
-Another example: ARM Cortex-M microcontrollers need their reset handler, a
-pointer to the function that will executed right after the microcontroller is
-turned on, to be placed near the start of their FLASH memory to boot properly.
-
-This condition can be met using `#[used]` and `#[link_section]` plus a linker
-script.
-
-``` rust,ignore
-#![feature(panic_handler)]
-#![feature(used)]
-#![no_main]
-#![no_std]
-
-use core::panic::PanicInfo;
-
-extern "C" fn reset_handler() -> ! {
-    loop {}
-}
-
-#[link_section = ".reset_handler"]
-#[used]
-static RESET_HANDLER: extern "C" fn() -> ! = reset_handler;
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
-    loop {}
-}
-```
-
-``` text
-MEMORY
-{
-  FLASH : ORIGIN = 0x08000000, LENGTH = 128K
-  RAM : ORIGIN = 0x20000000, LENGTH = 20K
-}
-
-SECTIONS
-{
-  .text ORIGIN(FLASH) :
-  {
-    /* Vector table */
-    LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */
-    KEEP(*(.reset_handler));
-
-    /* Omitted: The rest of the vector table */
-
-    *(.text.*);
-  } > FLASH
-
-  /DISCARD/ :
-  {
-    /* Unused unwinding stuff */
-    *(.ARM.exidx.*)
-  }
-}
-```
-
-``` text
-$ xargo rustc --target thumbv7m-none-eabi --release -- \
-    -C link-arg=-Tlink.x -C link-arg=-nostartfiles
-
-$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app
-./target/thumbv7m-none-eabi/release/app:     file format elf32-littlearm
-
-
-Disassembly of section .text:
-
-08000000 <app::RESET_HANDLER-0x4>:
- 8000000:       20005000        .word   0x20005000
-
-08000004 <app::RESET_HANDLER>:
- 8000004:       08000009                                ....
-
-08000008 <app::reset_handler>:
- 8000008:       e7fe            b.n     8000008 <app::reset_handler>
-```
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 5ae984a4b15..12da0455cc5 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -122,6 +122,9 @@ nonzero_integers! {
 /// all standard arithmetic operations on the underlying value are
 /// intended to have wrapping semantics.
 ///
+/// The underlying value can be retrieved through the `.0` index of the
+/// `Wrapping` tuple.
+///
 /// # Examples
 ///
 /// ```
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index c4b4a0fd72a..93ee11aac36 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -470,6 +470,36 @@ impl<T, E> Result<T, E> {
         }
     }
 
+    /// Maps a `Result<T, E>` to `U` by applying a function to a
+    /// contained [`Ok`] value, or a fallback function to a
+    /// contained [`Err`] value.
+    ///
+    /// This function can be used to unpack a successful result
+    /// while handling an error.
+    ///
+    /// [`Ok`]: enum.Result.html#variant.Ok
+    /// [`Err`]: enum.Result.html#variant.Err
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(result_map_or_else)]
+    /// let k = 21;
+    ///
+    /// let x : Result<_, &str> = Ok("foo");
+    /// assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3);
+    ///
+    /// let x : Result<&str, _> = Err("bar");
+    /// assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42);
+    /// ```
+    #[inline]
+    #[unstable(feature = "result_map_or_else", issue = "53268")]
+    pub fn map_or_else<U, M: FnOnce(T) -> U, F: FnOnce(E) -> U>(self, fallback: F, map: M) -> U {
+        self.map(map).unwrap_or_else(fallback)
+    }
+
     /// Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a
     /// contained [`Err`] value, leaving an [`Ok`] value untouched.
     ///
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index d4737052875..1de9cd35442 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -15,10 +15,6 @@
 //! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and
 //! custom derive attributes`#[proc_macro_derive]`.
 //!
-//! Note that this crate is intentionally bare-bones currently.
-//! This functionality is intended to be expanded over time as more surface
-//! area for macro authors is stabilized.
-//!
 //! See [the book](../book/first-edition/procedural-macros.html) for more.
 
 #![stable(feature = "proc_macro_lib", since = "1.15.0")]
@@ -73,9 +69,6 @@ use syntax_pos::{Pos, FileName};
 ///
 /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
 /// and `#[proc_macro_derive]` definitions.
-///
-/// The API of this type is intentionally bare-bones, but it'll be expanded over
-/// time!
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 #[derive(Clone)]
 pub struct TokenStream(tokenstream::TokenStream);
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index cab620aeec5..cf832aee534 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -76,23 +76,38 @@ impl<'a> DefCollector<'a> {
     fn visit_async_fn(
         &mut self,
         id: NodeId,
-        async_node_id: NodeId,
-        return_impl_trait_id: NodeId,
         name: Name,
         span: Span,
-        visit_fn: impl FnOnce(&mut DefCollector<'a>)
+        header: &FnHeader,
+        generics: &'a Generics,
+        decl: &'a FnDecl,
+        body: &'a Block,
     ) {
+        let (closure_id, return_impl_trait_id) = match header.asyncness {
+            IsAsync::Async {
+                closure_id,
+                return_impl_trait_id,
+            } => (closure_id, return_impl_trait_id),
+            _ => unreachable!(),
+        };
+
         // For async functions, we need to create their inner defs inside of a
         // closure to match their desugared representation.
         let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
         let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
         return self.with_parent(fn_def, |this| {
             this.create_def(return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span);
-            let closure_def = this.create_def(async_node_id,
+
+            visit::walk_generics(this, generics);
+            visit::walk_fn_decl(this, decl);
+
+            let closure_def = this.create_def(closure_id,
                                   DefPathData::ClosureExpr,
                                   REGULAR_SPACE,
                                   span);
-            this.with_parent(closure_def, visit_fn)
+            this.with_parent(closure_def, |this| {
+                visit::walk_block(this, body);
+            })
         })
     }
 
@@ -122,17 +137,20 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
             ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
                 return visit::walk_item(self, i);
             }
-            ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async {
-                closure_id,
-                return_impl_trait_id,
-            }, .. }, ..) => {
+            ItemKind::Fn(
+                ref decl,
+                ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
+                ref generics,
+                ref body,
+            ) => {
                 return self.visit_async_fn(
                     i.id,
-                    closure_id,
-                    return_impl_trait_id,
                     i.ident.name,
                     i.span,
-                    |this| visit::walk_item(this, i)
+                    header,
+                    generics,
+                    decl,
+                    body,
                 )
             }
             ItemKind::Mod(..) => DefPathData::Module(i.ident.as_interned_str()),
@@ -233,18 +251,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
     fn visit_impl_item(&mut self, ii: &'a ImplItem) {
         let def_data = match ii.node {
             ImplItemKind::Method(MethodSig {
-                header: FnHeader { asyncness: IsAsync::Async {
-                    closure_id,
-                    return_impl_trait_id,
-                }, .. }, ..
-            }, ..) => {
+                header: ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
+                ref decl,
+            }, ref body) => {
                 return self.visit_async_fn(
                     ii.id,
-                    closure_id,
-                    return_impl_trait_id,
                     ii.ident.name,
                     ii.span,
-                    |this| visit::walk_impl_item(this, ii)
+                    header,
+                    &ii.generics,
+                    decl,
+                    body,
                 )
             }
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 8b7438cbe63..5f35c9fea0a 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -24,6 +24,7 @@ impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
 impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
     mutability,
     ty,
+    user_ty,
     name,
     source_info,
     visibility_scope,
@@ -255,9 +256,10 @@ for mir::StatementKind<'gcx> {
                 op.hash_stable(hcx, hasher);
                 places.hash_stable(hcx, hasher);
             }
-            mir::StatementKind::UserAssertTy(ref c_ty, ref local) => {
+            mir::StatementKind::AscribeUserType(ref place, ref variance, ref c_ty) => {
+                place.hash_stable(hcx, hasher);
+                variance.hash_stable(hcx, hasher);
                 c_ty.hash_stable(hcx, hasher);
-                local.hash_stable(hcx, hasher);
             }
             mir::StatementKind::Nop => {}
             mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index a092bac5187..e628a3458f9 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -10,41 +10,41 @@
 
 //! See the Book for more information.
 
+pub use self::freshen::TypeFreshener;
 pub use self::LateBoundRegionConversionTime::*;
 pub use self::RegionVariableOrigin::*;
 pub use self::SubregionOrigin::*;
 pub use self::ValuePairs::*;
 pub use ty::IntVarValue;
-pub use self::freshen::TypeFreshener;
 
+use arena::SyncDroplessArena;
+use errors::DiagnosticBuilder;
 use hir::def_id::DefId;
 use middle::free_region::RegionRelations;
-use middle::region;
 use middle::lang_items;
-use ty::subst::{Kind, Substs};
-use ty::{TyVid, IntVid, FloatVid};
-use ty::{self, Ty, TyCtxt, GenericParamDefKind};
-use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
-use ty::fold::TypeFoldable;
-use ty::relate::RelateResult;
-use traits::{self, ObligationCause, PredicateObligations, TraitEngine};
+use middle::region;
 use rustc_data_structures::unify as ut;
-use std::cell::{Cell, RefCell, Ref, RefMut};
+use std::cell::{Cell, Ref, RefCell, RefMut};
 use std::collections::BTreeMap;
 use std::fmt;
 use syntax::ast;
-use errors::DiagnosticBuilder;
-use syntax_pos::{self, Span};
 use syntax_pos::symbol::InternedString;
+use syntax_pos::{self, Span};
+use traits::{self, ObligationCause, PredicateObligations, TraitEngine};
+use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
+use ty::fold::TypeFoldable;
+use ty::relate::RelateResult;
+use ty::subst::{Kind, Substs};
+use ty::{self, GenericParamDefKind, Ty, TyCtxt};
+use ty::{FloatVid, IntVid, TyVid};
 use util::nodemap::FxHashMap;
-use arena::SyncDroplessArena;
 
 use self::combine::CombineFields;
 use self::higher_ranked::HrMatchResult;
-use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
-use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarInfos};
 use self::lexical_region_resolve::LexicalRegionResolutions;
 use self::outlives::env::OutlivesEnvironment;
+use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
+use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
 use self::type_variable::TypeVariableOrigin;
 use self::unify_key::ToType;
 
@@ -54,16 +54,16 @@ pub mod canonical;
 mod combine;
 mod equate;
 pub mod error_reporting;
+mod freshen;
 mod fudge;
 mod glb;
 mod higher_ranked;
 pub mod lattice;
-mod lub;
-pub mod region_constraints;
 mod lexical_region_resolve;
+mod lub;
 pub mod outlives;
+pub mod region_constraints;
 pub mod resolve;
-mod freshen;
 mod sub;
 pub mod type_variable;
 pub mod unify_key;
@@ -80,7 +80,7 @@ pub type Bound<T> = Option<T>;
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
 pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 
-pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
     /// During type-checking/inference of a body, `in_progress_tables`
@@ -314,10 +314,10 @@ pub enum SubregionOrigin<'tcx> {
 /// Places that type/region parameters can appear.
 #[derive(Clone, Copy, Debug)]
 pub enum ParameterOrigin {
-    Path, // foo::bar
-    MethodCall, // foo.bar() <-- parameters on impl providing bar()
+    Path,               // foo::bar
+    MethodCall,         // foo.bar() <-- parameters on impl providing bar()
     OverloadedOperator, // a + b when overloaded
-    OverloadedDeref, // *a when overloaded
+    OverloadedDeref,    // *a when overloaded
 }
 
 /// Times when we replace late-bound regions with variables:
@@ -400,7 +400,7 @@ impl NLLRegionVariableOrigin {
 pub enum FixupError {
     UnresolvedIntTy(IntVid),
     UnresolvedFloatTy(FloatVid),
-    UnresolvedTy(TyVid)
+    UnresolvedTy(TyVid),
 }
 
 /// See the `region_obligations` field for more information.
@@ -416,15 +416,17 @@ impl fmt::Display for FixupError {
         use self::FixupError::*;
 
         match *self {
-            UnresolvedIntTy(_) => {
-                write!(f, "cannot determine the type of this integer; \
-                           add a suffix to specify the type explicitly")
-            }
-            UnresolvedFloatTy(_) => {
-                write!(f, "cannot determine the type of this number; \
-                           add a suffix to specify the type explicitly")
-            }
-            UnresolvedTy(_) => write!(f, "unconstrained type")
+            UnresolvedIntTy(_) => write!(
+                f,
+                "cannot determine the type of this integer; \
+                 add a suffix to specify the type explicitly"
+            ),
+            UnresolvedFloatTy(_) => write!(
+                f,
+                "cannot determine the type of this number; \
+                 add a suffix to specify the type explicitly"
+            ),
+            UnresolvedTy(_) => write!(f, "unconstrained type"),
         }
     }
 }
@@ -432,7 +434,7 @@ impl fmt::Display for FixupError {
 /// Helper type of a temporary returned by tcx.infer_ctxt().
 /// Necessary because we can't write the following bound:
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>).
-pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+pub struct InferCtxtBuilder<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
     arena: SyncDroplessArena,
     fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
@@ -444,7 +446,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
             global_tcx: self,
             arena: SyncDroplessArena::new(),
             fresh_tables: None,
-
         }
     }
 }
@@ -458,7 +459,8 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
     }
 
     pub fn enter<F, R>(&'tcx mut self, f: F) -> R
-        where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R
+    where
+        F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R,
     {
         let InferCtxtBuilder {
             global_tcx,
@@ -466,40 +468,51 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
             ref fresh_tables,
         } = *self;
         let in_progress_tables = fresh_tables.as_ref();
-        global_tcx.enter_local(arena, |tcx| f(InferCtxt {
-            tcx,
-            in_progress_tables,
-            projection_cache: RefCell::new(traits::ProjectionCache::new()),
-            type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
-            int_unification_table: RefCell::new(ut::UnificationTable::new()),
-            float_unification_table: RefCell::new(ut::UnificationTable::new()),
-            region_constraints: RefCell::new(Some(RegionConstraintCollector::new())),
-            lexical_region_resolutions: RefCell::new(None),
-            selection_cache: traits::SelectionCache::new(),
-            evaluation_cache: traits::EvaluationCache::new(),
-            reported_trait_errors: RefCell::new(FxHashMap()),
-            tainted_by_errors_flag: Cell::new(false),
-            err_count_on_creation: tcx.sess.err_count(),
-            in_snapshot: Cell::new(false),
-            region_obligations: RefCell::new(vec![]),
-            universe: Cell::new(ty::UniverseIndex::ROOT),
-        }))
+        global_tcx.enter_local(arena, |tcx| {
+            f(InferCtxt {
+                tcx,
+                in_progress_tables,
+                projection_cache: RefCell::new(traits::ProjectionCache::new()),
+                type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
+                int_unification_table: RefCell::new(ut::UnificationTable::new()),
+                float_unification_table: RefCell::new(ut::UnificationTable::new()),
+                region_constraints: RefCell::new(Some(RegionConstraintCollector::new())),
+                lexical_region_resolutions: RefCell::new(None),
+                selection_cache: traits::SelectionCache::new(),
+                evaluation_cache: traits::EvaluationCache::new(),
+                reported_trait_errors: RefCell::new(FxHashMap()),
+                tainted_by_errors_flag: Cell::new(false),
+                err_count_on_creation: tcx.sess.err_count(),
+                in_snapshot: Cell::new(false),
+                region_obligations: RefCell::new(vec![]),
+                universe: Cell::new(ty::UniverseIndex::ROOT),
+            })
+        })
     }
 }
 
 impl<T> ExpectedFound<T> {
     pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
         if a_is_expected {
-            ExpectedFound {expected: a, found: b}
+            ExpectedFound {
+                expected: a,
+                found: b,
+            }
         } else {
-            ExpectedFound {expected: b, found: a}
+            ExpectedFound {
+                expected: b,
+                found: a,
+            }
         }
     }
 }
 
 impl<'tcx, T> InferOk<'tcx, T> {
     pub fn unit(self) -> InferOk<'tcx, ()> {
-        InferOk { value: (), obligations: self.obligations }
+        InferOk {
+            value: (),
+            obligations: self.obligations,
+        }
     }
 
     /// Extract `value`, registering any obligations into `fulfill_cx`
@@ -523,7 +536,7 @@ impl<'tcx> InferOk<'tcx, ()> {
 }
 
 #[must_use = "once you start a snapshot, you should always consume it"]
-pub struct CombinedSnapshot<'a, 'tcx:'a> {
+pub struct CombinedSnapshot<'a, 'tcx: 'a> {
     projection_cache_snapshot: traits::ProjectionCacheSnapshot,
     type_snapshot: type_variable::Snapshot<'tcx>,
     int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
@@ -540,14 +553,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.in_snapshot.get()
     }
 
-    pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
+    pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
         t.fold_with(&mut self.freshener())
     }
 
     pub fn type_var_diverges(&'a self, ty: Ty) -> bool {
         match ty.sty {
             ty::Infer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid),
-            _ => false
+            _ => false,
         }
     }
 
@@ -557,22 +570,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric {
         use ty::error::UnconstrainedNumeric::Neither;
-        use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
+        use ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
         match ty.sty {
             ty::Infer(ty::IntVar(vid)) => {
-                if self.int_unification_table.borrow_mut().probe_value(vid).is_some() {
+                if self.int_unification_table
+                    .borrow_mut()
+                    .probe_value(vid)
+                    .is_some()
+                {
                     Neither
                 } else {
                     UnconstrainedInt
                 }
-            },
+            }
             ty::Infer(ty::FloatVar(vid)) => {
-                if self.float_unification_table.borrow_mut().probe_value(vid).is_some() {
+                if self.float_unification_table
+                    .borrow_mut()
+                    .probe_value(vid)
+                    .is_some()
+                {
                     Neither
                 } else {
                     UnconstrainedFloat
                 }
-            },
+            }
             _ => Neither,
         }
     }
@@ -590,17 +611,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 (0..int_unification_table.len())
                     .map(|i| ty::IntVid { index: i as u32 })
                     .filter(|&vid| int_unification_table.probe_value(vid).is_none())
-                    .map(|v| self.tcx.mk_int_var(v))
-            ).chain(
+                    .map(|v| self.tcx.mk_int_var(v)),
+            )
+            .chain(
                 (0..float_unification_table.len())
                     .map(|i| ty::FloatVid { index: i as u32 })
                     .filter(|&vid| float_unification_table.probe_value(vid).is_none())
-                    .map(|v| self.tcx.mk_float_var(v))
-            ).collect()
+                    .map(|v| self.tcx.mk_float_var(v)),
+            )
+            .collect()
     }
 
-    fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>)
-                      -> CombineFields<'a, 'gcx, 'tcx> {
+    fn combine_fields(
+        &'a self,
+        trace: TypeTrace<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> CombineFields<'a, 'gcx, 'tcx> {
         CombineFields {
             infcx: self,
             trace,
@@ -627,7 +653,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // escaping obligations in the main cx. In those cases, you can
     // use this function.
     pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
-        where F: FnOnce(&Self) -> R
+    where
+        F: FnOnce(&Self) -> R,
     {
         let flag = self.in_snapshot.get();
         self.in_snapshot.set(false);
@@ -653,23 +680,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             was_in_snapshot: in_snapshot,
             // Borrow tables "in progress" (i.e. during typeck)
             // to ban writes from within a snapshot to them.
-            _in_progress_tables: self.in_progress_tables.map(|tables| {
-                tables.borrow()
-            })
+            _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()),
         }
     }
 
     fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
         debug!("rollback_to(cause={})", cause);
-        let CombinedSnapshot { projection_cache_snapshot,
-                               type_snapshot,
-                               int_snapshot,
-                               float_snapshot,
-                               region_constraints_snapshot,
-                               region_obligations_snapshot,
-                               universe,
-                               was_in_snapshot,
-                               _in_progress_tables } = snapshot;
+        let CombinedSnapshot {
+            projection_cache_snapshot,
+            type_snapshot,
+            int_snapshot,
+            float_snapshot,
+            region_constraints_snapshot,
+            region_obligations_snapshot,
+            universe,
+            was_in_snapshot,
+            _in_progress_tables,
+        } = snapshot;
 
         self.in_snapshot.set(was_in_snapshot);
         self.universe.set(universe);
@@ -677,9 +704,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.projection_cache
             .borrow_mut()
             .rollback_to(projection_cache_snapshot);
-        self.type_variables
-            .borrow_mut()
-            .rollback_to(type_snapshot);
+        self.type_variables.borrow_mut().rollback_to(type_snapshot);
         self.int_unification_table
             .borrow_mut()
             .rollback_to(int_snapshot);
@@ -695,27 +720,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
         debug!("commit_from()");
-        let CombinedSnapshot { projection_cache_snapshot,
-                               type_snapshot,
-                               int_snapshot,
-                               float_snapshot,
-                               region_constraints_snapshot,
-                               region_obligations_snapshot: _,
-                               universe: _,
-                               was_in_snapshot,
-                               _in_progress_tables } = snapshot;
+        let CombinedSnapshot {
+            projection_cache_snapshot,
+            type_snapshot,
+            int_snapshot,
+            float_snapshot,
+            region_constraints_snapshot,
+            region_obligations_snapshot: _,
+            universe: _,
+            was_in_snapshot,
+            _in_progress_tables,
+        } = snapshot;
 
         self.in_snapshot.set(was_in_snapshot);
 
         self.projection_cache
             .borrow_mut()
             .commit(&projection_cache_snapshot);
-        self.type_variables
-            .borrow_mut()
-            .commit(type_snapshot);
-        self.int_unification_table
-            .borrow_mut()
-            .commit(int_snapshot);
+        self.type_variables.borrow_mut().commit(type_snapshot);
+        self.int_unification_table.borrow_mut().commit(int_snapshot);
         self.float_unification_table
             .borrow_mut()
             .commit(float_snapshot);
@@ -724,7 +747,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Execute `f` and commit the bindings
-    pub fn commit_unconditionally<R, F>(&self, f: F) -> R where
+    pub fn commit_unconditionally<R, F>(&self, f: F) -> R
+    where
         F: FnOnce() -> R,
     {
         debug!("commit()");
@@ -735,23 +759,29 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`
-    pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>
+    pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
+    where
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
     {
         debug!("commit_if_ok()");
         let snapshot = self.start_snapshot();
         let r = f(&snapshot);
         debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
         match r {
-            Ok(_) => { self.commit_from(snapshot); }
-            Err(_) => { self.rollback_to("commit_if_ok -- error", snapshot); }
+            Ok(_) => {
+                self.commit_from(snapshot);
+            }
+            Err(_) => {
+                self.rollback_to("commit_if_ok -- error", snapshot);
+            }
         }
         r
     }
 
     // Execute `f` in a snapshot, and commit the bindings it creates
-    pub fn in_snapshot<T, F>(&self, f: F) -> T where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T
+    pub fn in_snapshot<T, F>(&self, f: F) -> T
+    where
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T,
     {
         debug!("in_snapshot()");
         let snapshot = self.start_snapshot();
@@ -761,7 +791,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Execute `f` then unroll any bindings it creates
-    pub fn probe<R, F>(&self, f: F) -> R where
+    pub fn probe<R, F>(&self, f: F) -> R
+    where
         F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
     {
         debug!("probe()");
@@ -771,59 +802,57 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         r
     }
 
-    pub fn add_given(&self,
-                     sub: ty::Region<'tcx>,
-                     sup: ty::RegionVid)
-    {
+    pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
         self.borrow_region_constraints().add_given(sub, sup);
     }
 
-    pub fn can_sub<T>(&self,
-                      param_env: ty::ParamEnv<'tcx>,
-                      a: T,
-                      b: T)
-                      -> UnitResult<'tcx>
-        where T: at::ToTrace<'tcx>
+    pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
+    where
+        T: at::ToTrace<'tcx>,
     {
         let origin = &ObligationCause::dummy();
         self.probe(|_| {
-            self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| {
-                // Ignore obligations, since we are unrolling
-                // everything anyway.
-            })
+            self.at(origin, param_env)
+                .sub(a, b)
+                .map(|InferOk { obligations: _, .. }| {
+                    // Ignore obligations, since we are unrolling
+                    // everything anyway.
+                })
         })
     }
 
-    pub fn can_eq<T>(&self,
-                      param_env: ty::ParamEnv<'tcx>,
-                      a: T,
-                      b: T)
-                      -> UnitResult<'tcx>
-        where T: at::ToTrace<'tcx>
+    pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
+    where
+        T: at::ToTrace<'tcx>,
     {
         let origin = &ObligationCause::dummy();
         self.probe(|_| {
-            self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| {
-                // Ignore obligations, since we are unrolling
-                // everything anyway.
-            })
+            self.at(origin, param_env)
+                .eq(a, b)
+                .map(|InferOk { obligations: _, .. }| {
+                    // Ignore obligations, since we are unrolling
+                    // everything anyway.
+                })
         })
     }
 
-    pub fn sub_regions(&self,
-                       origin: SubregionOrigin<'tcx>,
-                       a: ty::Region<'tcx>,
-                       b: ty::Region<'tcx>) {
+    pub fn sub_regions(
+        &self,
+        origin: SubregionOrigin<'tcx>,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) {
         debug!("sub_regions({:?} <: {:?})", a, b);
-        self.borrow_region_constraints().make_subregion(origin, a, b);
+        self.borrow_region_constraints()
+            .make_subregion(origin, a, b);
     }
 
-    pub fn subtype_predicate(&self,
-                             cause: &ObligationCause<'tcx>,
-                             param_env: ty::ParamEnv<'tcx>,
-                             predicate: &ty::PolySubtypePredicate<'tcx>)
-        -> Option<InferResult<'tcx, ()>>
-    {
+    pub fn subtype_predicate(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        predicate: &ty::PolySubtypePredicate<'tcx>,
+    ) -> Option<InferResult<'tcx, ()>> {
         // Subtle: it's ok to skip the binder here and resolve because
         // `shallow_resolve` just ignores anything that is not a type
         // variable, and because type variable's can't (at present, at
@@ -845,8 +874,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
 
         Some(self.commit_if_ok(|snapshot| {
-            let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) =
-                self.skolemize_late_bound_regions(predicate);
+            let (
+                ty::SubtypePredicate {
+                    a_is_expected,
+                    a,
+                    b,
+                },
+                skol_map,
+            ) = self.skolemize_late_bound_regions(predicate);
 
             let cause_span = cause.span;
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
@@ -856,17 +891,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }))
     }
 
-    pub fn region_outlives_predicate(&self,
-                                     cause: &traits::ObligationCause<'tcx>,
-                                     predicate: &ty::PolyRegionOutlivesPredicate<'tcx>)
-        -> UnitResult<'tcx>
-    {
+    pub fn region_outlives_predicate(
+        &self,
+        cause: &traits::ObligationCause<'tcx>,
+        predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
+    ) -> UnitResult<'tcx> {
         self.commit_if_ok(|snapshot| {
             let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
                 self.skolemize_late_bound_regions(predicate);
-            let origin =
-                SubregionOrigin::from_obligation_cause(cause,
-                                                       || RelateRegionParamBound(cause.span));
+            let origin = SubregionOrigin::from_obligation_cause(cause, || {
+                RelateRegionParamBound(cause.span)
+            });
             self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
             self.leak_check(false, cause.span, &skol_map, snapshot)?;
             Ok(self.pop_skolemized(skol_map, snapshot))
@@ -888,27 +923,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn next_int_var_id(&self) -> IntVid {
-        self.int_unification_table
-            .borrow_mut()
-            .new_key(None)
+        self.int_unification_table.borrow_mut().new_key(None)
     }
 
     pub fn next_float_var_id(&self) -> FloatVid {
-        self.float_unification_table
-            .borrow_mut()
-            .new_key(None)
+        self.float_unification_table.borrow_mut().new_key(None)
     }
 
     /// Create a fresh region variable with the next available index.
-    ///
-    /// # Parameters
-    ///
-    /// - `origin`: information about why we created this variable, for use
-    ///   during diagnostics / error-reporting.
-    pub fn next_region_var(&self, origin: RegionVariableOrigin)
-                           -> ty::Region<'tcx> {
+    /// The variable will be created in the maximum universe created
+    /// thus far, allowing it to name any region created thus far.
+    pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> {
+        self.next_region_var_in_universe(origin, self.universe())
+    }
+
+    /// Create a fresh region variable with the next available index
+    /// in the given universe; typically, you can use
+    /// `next_region_var` and just use the maximal universe.
+    pub fn next_region_var_in_universe(
+        &self,
+        origin: RegionVariableOrigin,
+        universe: ty::UniverseIndex,
+    ) -> ty::Region<'tcx> {
         let region_var = self.borrow_region_constraints()
-            .new_region_var(self.universe(), origin);
+            .new_region_var(universe, origin);
         self.tcx.mk_region(ty::ReVar(region_var))
     }
 
@@ -918,22 +956,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Just a convenient wrapper of `next_region_var` for using during NLL.
-    pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin)
-                               -> ty::Region<'tcx> {
+    pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> {
         self.next_region_var(RegionVariableOrigin::NLL(origin))
     }
 
-    pub fn var_for_def(&self,
-                       span: Span,
-                       param: &ty::GenericParamDef)
-                       -> Kind<'tcx> {
+    /// Just a convenient wrapper of `next_region_var` for using during NLL.
+    pub fn next_nll_region_var_in_universe(
+        &self,
+        origin: NLLRegionVariableOrigin,
+        universe: ty::UniverseIndex,
+    ) -> ty::Region<'tcx> {
+        self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe)
+    }
+
+    pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> Kind<'tcx> {
         match param.kind {
             GenericParamDefKind::Lifetime => {
                 // Create a region inference variable for the given
                 // region parameter definition.
-                self.next_region_var(EarlyBoundRegion(span, param.name)).into()
+                self.next_region_var(EarlyBoundRegion(span, param.name))
+                    .into()
             }
-            GenericParamDefKind::Type {..} => {
+            GenericParamDefKind::Type { .. } => {
                 // Create a type inference variable for the given
                 // type parameter definition. The substitutions are
                 // for actual parameters that may be referred to by
@@ -942,12 +986,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 // used in a path such as `Foo::<T, U>::new()` will
                 // use an inference variable for `C` with `[T, U]`
                 // as the substitutions for the default, `(T, U)`.
-                let ty_var_id =
-                    self.type_variables
-                        .borrow_mut()
-                        .new_var(self.universe(),
-                                    false,
-                                    TypeVariableOrigin::TypeParameterDefinition(span, param.name));
+                let ty_var_id = self.type_variables.borrow_mut().new_var(
+                    self.universe(),
+                    false,
+                    TypeVariableOrigin::TypeParameterDefinition(span, param.name),
+                );
 
                 self.tcx.mk_var(ty_var_id).into()
             }
@@ -956,13 +999,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
     /// type/region parameter to a fresh inference variable.
-    pub fn fresh_substs_for_item(&self,
-                                 span: Span,
-                                 def_id: DefId)
-                                 -> &'tcx Substs<'tcx> {
-        Substs::for_item(self.tcx, def_id, |param, _| {
-            self.var_for_def(span, param)
-        })
+    pub fn fresh_substs_for_item(&self, span: Span, def_id: DefId) -> &'tcx Substs<'tcx> {
+        Substs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param))
     }
 
     /// True if errors have been reported since this infcx was
@@ -971,11 +1009,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// errors, but where it's hard to be 100% sure (e.g., unresolved
     /// inference variables, regionck errors).
     pub fn is_tainted_by_errors(&self) -> bool {
-        debug!("is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
-                tainted_by_errors_flag={})",
-               self.tcx.sess.err_count(),
-               self.err_count_on_creation,
-               self.tainted_by_errors_flag.get());
+        debug!(
+            "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
+             tainted_by_errors_flag={})",
+            self.tcx.sess.err_count(),
+            self.err_count_on_creation,
+            self.tainted_by_errors_flag.get()
+        );
 
         if self.tcx.sess.err_count() > self.err_count_on_creation {
             return true; // errors reported since this infcx was made
@@ -1018,12 +1058,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         region_map: &region::ScopeTree,
         outlives_env: &OutlivesEnvironment<'tcx>,
     ) {
-        self.resolve_regions_and_report_errors_inner(
-            region_context,
-            region_map,
-            outlives_env,
-            true,
-        )
+        self.resolve_regions_and_report_errors_inner(region_context, region_map, outlives_env, true)
     }
 
     fn resolve_regions_and_report_errors_inner(
@@ -1033,22 +1068,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         outlives_env: &OutlivesEnvironment<'tcx>,
         will_later_be_reported_by_nll: bool,
     ) {
-        assert!(self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
-                "region_obligations not empty: {:#?}",
-                self.region_obligations.borrow());
-
-        let region_rels = &RegionRelations::new(self.tcx,
-                                                region_context,
-                                                region_map,
-                                                outlives_env.free_region_map());
-        let (var_infos, data) = self.region_constraints.borrow_mut()
-                                                         .take()
-                                                         .expect("regions already resolved")
-                                                         .into_infos_and_data();
+        assert!(
+            self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
+            "region_obligations not empty: {:#?}",
+            self.region_obligations.borrow()
+        );
+
+        let region_rels = &RegionRelations::new(
+            self.tcx,
+            region_context,
+            region_map,
+            outlives_env.free_region_map(),
+        );
+        let (var_infos, data) = self.region_constraints
+            .borrow_mut()
+            .take()
+            .expect("regions already resolved")
+            .into_infos_and_data();
         let (lexical_region_resolutions, errors) =
             lexical_region_resolve::resolve(region_rels, var_infos, data);
 
-        let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
+        let old_value = self.lexical_region_resolutions
+            .replace(Some(lexical_region_resolutions));
         assert!(old_value.is_none());
 
         if !self.is_tainted_by_errors() {
@@ -1072,9 +1113,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// translate them into the form that the NLL solver
     /// understands. See the NLL module for mode details.
     pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
-        assert!(self.region_obligations.borrow().is_empty(),
-                "region_obligations not empty: {:#?}",
-                self.region_obligations.borrow());
+        assert!(
+            self.region_obligations.borrow().is_empty(),
+            "region_obligations not empty: {:#?}",
+            self.region_obligations.borrow()
+        );
 
         self.borrow_region_constraints().take_and_reset_data()
     }
@@ -1095,10 +1138,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// called. This is used only during NLL processing to "hand off" ownership
     /// of the set of region vairables into the NLL region context.
     pub fn take_region_var_origins(&self) -> VarInfos {
-        let (var_infos, data) = self.region_constraints.borrow_mut()
-                                                         .take()
-                                                         .expect("regions already resolved")
-                                                         .into_infos_and_data();
+        let (var_infos, data) = self.region_constraints
+            .borrow_mut()
+            .take()
+            .expect("regions already resolved")
+            .into_infos_and_data();
         assert!(data.is_empty());
         var_infos
     }
@@ -1132,32 +1176,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 // structurally), and we prevent cycles in any case,
                 // so this recursion should always be of very limited
                 // depth.
-                self.type_variables.borrow_mut()
-                                   .probe(v)
-                                   .known()
-                                   .map(|t| self.shallow_resolve(t))
-                                   .unwrap_or(typ)
-            }
-
-            ty::Infer(ty::IntVar(v)) => {
-                self.int_unification_table
+                self.type_variables
                     .borrow_mut()
-                    .probe_value(v)
-                    .map(|v| v.to_type(self.tcx))
+                    .probe(v)
+                    .known()
+                    .map(|t| self.shallow_resolve(t))
                     .unwrap_or(typ)
             }
 
-            ty::Infer(ty::FloatVar(v)) => {
-                self.float_unification_table
-                    .borrow_mut()
-                    .probe_value(v)
-                    .map(|v| v.to_type(self.tcx))
-                    .unwrap_or(typ)
-            }
+            ty::Infer(ty::IntVar(v)) => self.int_unification_table
+                .borrow_mut()
+                .probe_value(v)
+                .map(|v| v.to_type(self.tcx))
+                .unwrap_or(typ),
 
-            _ => {
-                typ
-            }
+            ty::Infer(ty::FloatVar(v)) => self.float_unification_table
+                .borrow_mut()
+                .probe_value(v)
+                .map(|v| v.to_type(self.tcx))
+                .unwrap_or(typ),
+
+            _ => typ,
         }
     }
 
@@ -1166,7 +1205,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
-        where T: TypeFoldable<'tcx>
+    where
+        T: TypeFoldable<'tcx>,
     {
         /*!
          * Where possible, replaces type/int/float variables in
@@ -1190,20 +1230,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// resolved type, so it's more efficient than
     /// `resolve_type_vars_if_possible()`.
     pub fn any_unresolved_type_vars<T>(&self, value: &T) -> bool
-        where T: TypeFoldable<'tcx>
+    where
+        T: TypeFoldable<'tcx>,
     {
         let mut r = resolve::UnresolvedTypeFinder::new(self);
         value.visit_with(&mut r)
     }
 
     pub fn resolve_type_and_region_vars_if_possible<T>(&self, value: &T) -> T
-        where T: TypeFoldable<'tcx>
+    where
+        T: TypeFoldable<'tcx>,
     {
         let mut r = resolve::OpportunisticTypeAndRegionResolver::new(self);
         value.fold_with(&mut r)
     }
 
-    pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
+    pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
         /*!
          * Attempts to resolve all type/region variables in
          * `value`. Region inference must have been run already (e.g.,
@@ -1228,12 +1270,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // types using one of these methods, and should not call span_err directly for such
     // errors.
 
-    pub fn type_error_struct_with_diag<M>(&self,
-                                          sp: Span,
-                                          mk_diag: M,
-                                          actual_ty: Ty<'tcx>)
-                                          -> DiagnosticBuilder<'tcx>
-        where M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
+    pub fn type_error_struct_with_diag<M>(
+        &self,
+        sp: Span,
+        mk_diag: M,
+        actual_ty: Ty<'tcx>,
+    ) -> DiagnosticBuilder<'tcx>
+    where
+        M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
     {
         let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
         debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
@@ -1246,12 +1290,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         mk_diag(self.ty_to_string(actual_ty))
     }
 
-    pub fn report_mismatched_types(&self,
-                                   cause: &ObligationCause<'tcx>,
-                                   expected: Ty<'tcx>,
-                                   actual: Ty<'tcx>,
-                                   err: TypeError<'tcx>)
-                                   -> DiagnosticBuilder<'tcx> {
+    pub fn report_mismatched_types(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+        err: TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx> {
         let trace = TypeTrace::types(cause, true, expected, actual);
         self.report_and_explain_type_error(trace, &err)
     }
@@ -1260,13 +1305,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         &self,
         span: Span,
         lbrct: LateBoundRegionConversionTime,
-        value: &ty::Binder<T>)
-        -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
-        where T : TypeFoldable<'tcx>
+        value: &ty::Binder<T>,
+    ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
+    where
+        T: TypeFoldable<'tcx>,
     {
-        self.tcx.replace_late_bound_regions(
-            value,
-            |br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
+        self.tcx.replace_late_bound_regions(value, |br| {
+            self.next_region_var(LateBoundRegion(span, br, lbrct))
+        })
     }
 
     /// Given a higher-ranked projection predicate like:
@@ -1284,43 +1330,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     ///
     /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more
     /// details.
-    pub fn match_poly_projection_predicate(&self,
-                                           cause: ObligationCause<'tcx>,
-                                           param_env: ty::ParamEnv<'tcx>,
-                                           match_a: ty::PolyProjectionPredicate<'tcx>,
-                                           match_b: ty::TraitRef<'tcx>)
-                                           -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
-    {
+    pub fn match_poly_projection_predicate(
+        &self,
+        cause: ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        match_a: ty::PolyProjectionPredicate<'tcx>,
+        match_b: ty::TraitRef<'tcx>,
+    ) -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> {
         let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
         let trace = TypeTrace {
             cause,
-            values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b))
+            values: TraitRefs(ExpectedFound::new(
+                true,
+                match_pair.skip_binder().0,
+                match_b,
+            )),
         };
 
         let mut combine = self.combine_fields(trace, param_env);
         let result = combine.higher_ranked_match(&match_pair, &match_b, true)?;
-        Ok(InferOk { value: result, obligations: combine.obligations })
+        Ok(InferOk {
+            value: result,
+            obligations: combine.obligations,
+        })
     }
 
     /// See `verify_generic_bound` method in `region_constraints`
-    pub fn verify_generic_bound(&self,
-                                origin: SubregionOrigin<'tcx>,
-                                kind: GenericKind<'tcx>,
-                                a: ty::Region<'tcx>,
-                                bound: VerifyBound<'tcx>) {
-        debug!("verify_generic_bound({:?}, {:?} <: {:?})",
-               kind,
-               a,
-               bound);
-
-        self.borrow_region_constraints().verify_generic_bound(origin, kind, a, bound);
-    }
-
-    pub fn type_moves_by_default(&self,
-                                 param_env: ty::ParamEnv<'tcx>,
-                                 ty: Ty<'tcx>,
-                                 span: Span)
-                                 -> bool {
+    pub fn verify_generic_bound(
+        &self,
+        origin: SubregionOrigin<'tcx>,
+        kind: GenericKind<'tcx>,
+        a: ty::Region<'tcx>,
+        bound: VerifyBound<'tcx>,
+    ) {
+        debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, bound);
+
+        self.borrow_region_constraints()
+            .verify_generic_bound(origin, kind, a, bound);
+    }
+
+    pub fn type_moves_by_default(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) -> bool {
         let ty = self.resolve_type_vars_if_possible(&ty);
         // Even if the type may have no inference variables, during
         // type-checking closure types are in local tables only.
@@ -1342,11 +1396,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// Obtains the latest type of the given closure; this may be a
     /// closure in the current function, in which case its
     /// `ClosureKind` may not yet be known.
-    pub fn closure_kind(&self,
-                        closure_def_id: DefId,
-                        closure_substs: ty::ClosureSubsts<'tcx>)
-                        -> Option<ty::ClosureKind>
-    {
+    pub fn closure_kind(
+        &self,
+        closure_def_id: DefId,
+        closure_substs: ty::ClosureSubsts<'tcx>,
+    ) -> Option<ty::ClosureKind> {
         let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
         let closure_kind_ty = self.shallow_resolve(&closure_kind_ty);
         closure_kind_ty.to_opt_closure_kind()
@@ -1359,7 +1413,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn closure_sig(
         &self,
         def_id: DefId,
-        substs: ty::ClosureSubsts<'tcx>
+        substs: ty::ClosureSubsts<'tcx>,
     ) -> ty::PolyFnSig<'tcx> {
         let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx);
         let closure_sig_ty = self.shallow_resolve(&closure_sig_ty);
@@ -1368,29 +1422,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     /// Normalizes associated types in `value`, potentially returning
     /// new obligations that must further be processed.
-    pub fn partially_normalize_associated_types_in<T>(&self,
-                                                      span: Span,
-                                                      body_id: ast::NodeId,
-                                                      param_env: ty::ParamEnv<'tcx>,
-                                                      value: &T)
-                                                      -> InferOk<'tcx, T>
-        where T : TypeFoldable<'tcx>
+    pub fn partially_normalize_associated_types_in<T>(
+        &self,
+        span: Span,
+        body_id: ast::NodeId,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &T,
+    ) -> InferOk<'tcx, T>
+    where
+        T: TypeFoldable<'tcx>,
     {
         debug!("partially_normalize_associated_types_in(value={:?})", value);
         let mut selcx = traits::SelectionContext::new(self);
         let cause = ObligationCause::misc(span, body_id);
         let traits::Normalized { value, obligations } =
             traits::normalize(&mut selcx, param_env, cause, value);
-        debug!("partially_normalize_associated_types_in: result={:?} predicates={:?}",
-            value,
-            obligations);
+        debug!(
+            "partially_normalize_associated_types_in: result={:?} predicates={:?}",
+            value, obligations
+        );
         InferOk { value, obligations }
     }
 
     pub fn borrow_region_constraints(&self) -> RefMut<'_, RegionConstraintCollector<'tcx>> {
-        RefMut::map(
-            self.region_constraints.borrow_mut(),
-            |c| c.as_mut().expect("region constraints already solved"))
+        RefMut::map(self.region_constraints.borrow_mut(), |c| {
+            c.as_mut().expect("region constraints already solved")
+        })
     }
 
     /// Clears the selection, evaluation, and projection cachesThis is useful when
@@ -1423,14 +1480,15 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
         self.cause.span
     }
 
-    pub fn types(cause: &ObligationCause<'tcx>,
-                 a_is_expected: bool,
-                 a: Ty<'tcx>,
-                 b: Ty<'tcx>)
-                 -> TypeTrace<'tcx> {
+    pub fn types(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+    ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: Types(ExpectedFound::new(a_is_expected, a, b))
+            values: Types(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 
@@ -1440,7 +1498,7 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
             values: Types(ExpectedFound {
                 expected: tcx.types.err,
                 found: tcx.types.err,
-            })
+            }),
         }
     }
 }
@@ -1482,24 +1540,25 @@ impl<'tcx> SubregionOrigin<'tcx> {
         }
     }
 
-    pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>,
-                                    default: F)
-                                    -> Self
-        where F: FnOnce() -> Self
+    pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default: F) -> Self
+    where
+        F: FnOnce() -> Self,
     {
         match cause.code {
-            traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) =>
-                SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span),
-
-            traits::ObligationCauseCode::CompareImplMethodObligation { item_name,
-                                                                       impl_item_def_id,
-                                                                       trait_item_def_id, } =>
-                SubregionOrigin::CompareImplMethodObligation {
-                    span: cause.span,
-                    item_name,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                },
+            traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => {
+                SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
+            }
+
+            traits::ObligationCauseCode::CompareImplMethodObligation {
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => SubregionOrigin::CompareImplMethodObligation {
+                span: cause.span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            },
 
             _ => default(),
         }
@@ -1534,8 +1593,10 @@ EnumTypeFoldableImpl! {
 
 impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
-               self.sub_region,
-               self.sup_type)
+        write!(
+            f,
+            "RegionObligation(sub_region={:?}, sup_type={:?})",
+            self.sub_region, self.sup_type
+        )
     }
 }
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index b823545aa91..e22792305a0 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1117,6 +1117,13 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
     }
 
     fn visit_mac(&mut self, mac: &'a ast::Mac) {
+        // FIXME(#54110): So, this setup isn't really right. I think
+        // that (a) the libsyntax visitor ought to be doing this as
+        // part of `walk_mac`, and (b) we should be calling
+        // `visit_path`, *but* that would require a `NodeId`, and I
+        // want to get #53686 fixed quickly. -nmatsakis
+        ast_visit::walk_path(self, &mac.node.path);
+
         run_lints!(self, check_mac, mac);
     }
 }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index cc0548c0dff..8d2851d1b77 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -53,7 +53,7 @@ use ty::query::Providers;
 use util::nodemap::NodeMap;
 
 pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
-                        check_crate, check_ast_crate,
+                        check_crate, check_ast_crate, CheckLintNameResult,
                         FutureIncompatibleInfo, BufferedEarlyLint};
 
 /// Specification of a single lint.
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 708ce8e2031..3450eec8082 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -640,6 +640,12 @@ pub struct LocalDecl<'tcx> {
     /// Type of this local.
     pub ty: Ty<'tcx>,
 
+    /// If the user manually ascribed a type to this variable,
+    /// e.g. via `let x: T`, then we carry that type here. The MIR
+    /// borrow checker needs this information since it can affect
+    /// region inference.
+    pub user_ty: Option<CanonicalTy<'tcx>>,
+
     /// Name of the local, used in debuginfo and pretty-printing.
     ///
     /// Note that function arguments can also have this set to `Some(_)`
@@ -802,6 +808,7 @@ impl<'tcx> LocalDecl<'tcx> {
         LocalDecl {
             mutability,
             ty,
+            user_ty: None,
             name: None,
             source_info: SourceInfo {
                 span,
@@ -821,6 +828,7 @@ impl<'tcx> LocalDecl<'tcx> {
         LocalDecl {
             mutability: Mutability::Mut,
             ty: return_ty,
+            user_ty: None,
             source_info: SourceInfo {
                 span,
                 scope: OUTERMOST_SOURCE_SCOPE,
@@ -1636,22 +1644,19 @@ pub enum StatementKind<'tcx> {
     /// (The starting point(s) arise implicitly from borrows.)
     EndRegion(region::Scope),
 
-    /// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect
-    /// them. For example:
-    ///
-    ///     let (a, b): (T, U) = y;
-    ///
-    /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y`
-    /// is the right thing.
+    /// Encodes a user's type ascription. These need to be preserved
+    /// intact so that NLL can respect them. For example:
     ///
-    /// `CanonicalTy` is used to capture "inference variables" from the user's types. For example:
+    ///     let a: T = y;
     ///
-    ///     let x: Vec<_> = ...;
-    ///     let y: &u32 = ...;
+    /// The effect of this annotation is to relate the type `T_y` of the place `y`
+    /// to the user-given type `T`. The effect depends on the specified variance:
     ///
-    /// would result in `Vec<?0>` and `&'?0 u32` respectively (where `?0` is a canonicalized
-    /// variable).
-    UserAssertTy(CanonicalTy<'tcx>, Local),
+    /// - `Covariant` -- requires that `T_y <: T`
+    /// - `Contravariant` -- requires that `T_y :> T`
+    /// - `Invariant` -- requires that `T_y == T`
+    /// - `Bivariant` -- no effect
+    AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
@@ -1728,8 +1733,8 @@ impl<'tcx> Debug for Statement<'tcx> {
                 ref outputs,
                 ref inputs,
             } => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs),
-            UserAssertTy(ref c_ty, ref local) => {
-                write!(fmt, "UserAssertTy({:?}, {:?})", c_ty, local)
+            AscribeUserType(ref place, ref variance, ref c_ty) => {
+                write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
             }
             Nop => write!(fmt, "nop"),
         }
@@ -2616,6 +2621,7 @@ BraceStructTypeFoldableImpl! {
         is_user_variable,
         internal,
         ty,
+        user_ty,
         name,
         source_info,
         visibility_scope,
@@ -2652,7 +2658,7 @@ EnumTypeFoldableImpl! {
         (StatementKind::InlineAsm) { asm, outputs, inputs },
         (StatementKind::Validate)(a, b),
         (StatementKind::EndRegion)(a),
-        (StatementKind::UserAssertTy)(a, b),
+        (StatementKind::AscribeUserType)(a, v, b),
         (StatementKind::Nop),
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index c7723fdf191..0beb5ac0a3c 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -144,11 +144,12 @@ macro_rules! make_mir_visitor {
                 self.super_operand(operand, location);
             }
 
-            fn visit_user_assert_ty(&mut self,
-                                    c_ty: & $($mutability)* CanonicalTy<'tcx>,
-                                    local: & $($mutability)* Local,
-                                    location: Location) {
-                self.super_user_assert_ty(c_ty, local, location);
+            fn visit_ascribe_user_ty(&mut self,
+                                     place: & $($mutability)* Place<'tcx>,
+                                     variance: & $($mutability)* ty::Variance,
+                                     c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                     location: Location) {
+                self.super_ascribe_user_ty(place, variance, c_ty, location);
             }
 
             fn visit_place(&mut self,
@@ -386,9 +387,12 @@ macro_rules! make_mir_visitor {
                             self.visit_operand(input, location);
                         }
                     }
-                    StatementKind::UserAssertTy(ref $($mutability)* c_ty,
-                                                ref $($mutability)* local) => {
-                        self.visit_user_assert_ty(c_ty, local, location);
+                    StatementKind::AscribeUserType(
+                        ref $($mutability)* place,
+                        ref $($mutability)* variance,
+                        ref $($mutability)* c_ty,
+                    ) => {
+                        self.visit_ascribe_user_ty(place, variance, c_ty, location);
                     }
                     StatementKind::Nop => {}
                 }
@@ -629,12 +633,13 @@ macro_rules! make_mir_visitor {
                 }
             }
 
-            fn super_user_assert_ty(&mut self,
-                                    c_ty: & $($mutability)* CanonicalTy<'tcx>,
-                                    local: & $($mutability)* Local,
-                                    location: Location) {
+            fn super_ascribe_user_ty(&mut self,
+                                     place: & $($mutability)* Place<'tcx>,
+                                     _variance: & $($mutability)* ty::Variance,
+                                     c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                     location: Location) {
+                self.visit_place(place, PlaceContext::Validate, location);
                 self.visit_canonical_ty(c_ty);
-                self.visit_local(local, PlaceContext::Validate, location);
             }
 
             fn super_place(&mut self,
@@ -716,6 +721,7 @@ macro_rules! make_mir_visitor {
                 let LocalDecl {
                     mutability: _,
                     ref $($mutability)* ty,
+                    ref $($mutability)* user_ty,
                     name: _,
                     ref $($mutability)* source_info,
                     ref $($mutability)* visibility_scope,
@@ -727,6 +733,9 @@ macro_rules! make_mir_visitor {
                     local,
                     source_info: *source_info,
                 });
+                if let Some(user_ty) = user_ty {
+                    self.visit_canonical_ty(user_ty);
+                }
                 self.visit_source_info(source_info);
                 self.visit_source_scope(visibility_scope);
             }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index ddaa0444cc7..6cc648b572c 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -356,8 +356,8 @@ pub struct TypeckTables<'tcx> {
     /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
     field_indices: ItemLocalMap<usize>,
 
-    /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
-    /// MIR.
+    /// Stores the canonicalized types provided by the user. See also
+    /// `AscribeUserType` statement in MIR.
     user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
 
     /// Stores the types for various nodes in the AST.  Note that this table
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 955f2740b92..bd9dfc6b855 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
     ::ty::ClosureKind,
     ::ty::IntVarValue,
     ::ty::ParamTy,
+    ::ty::Variance,
     ::syntax_pos::Span,
 }
 
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index b6ffcd55d91..696c4d0043c 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -42,7 +42,7 @@ const TAG_MASK: usize = 0b11;
 const TYPE_TAG: usize = 0b00;
 const REGION_TAG: usize = 0b01;
 
-#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord)]
 pub enum UnpackedKind<'tcx> {
     Lifetime(ty::Region<'tcx>),
     Type(Ty<'tcx>),
@@ -74,17 +74,7 @@ impl<'tcx> UnpackedKind<'tcx> {
 
 impl<'tcx> Ord for Kind<'tcx> {
     fn cmp(&self, other: &Kind) -> Ordering {
-        match (self.unpack(), other.unpack()) {
-            (UnpackedKind::Type(_), UnpackedKind::Lifetime(_)) => Ordering::Greater,
-
-            (UnpackedKind::Type(ty1), UnpackedKind::Type(ty2)) => {
-                ty1.sty.cmp(&ty2.sty)
-            }
-
-            (UnpackedKind::Lifetime(reg1), UnpackedKind::Lifetime(reg2)) => reg1.cmp(reg2),
-
-            (UnpackedKind::Lifetime(_), UnpackedKind::Type(_))  => Ordering::Less,
-        }
+        self.unpack().cmp(&other.unpack())
     }
 }
 
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index c8a2b47e98d..51380db5b23 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -16,6 +16,7 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::session::Session;
 use rustc::session::config::Sanitizer;
 use rustc::ty::TyCtxt;
+use rustc::ty::layout::HasTyCtxt;
 use rustc::ty::query::Providers;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::fx::FxHashMap;
@@ -32,12 +33,16 @@ use value::Value;
 
 /// Mark LLVM function to use provided inline heuristic.
 #[inline]
-pub fn inline(val: &'ll Value, inline: InlineAttr) {
+pub fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
     use self::InlineAttr::*;
     match inline {
         Hint   => Attribute::InlineHint.apply_llfn(Function, val),
         Always => Attribute::AlwaysInline.apply_llfn(Function, val),
-        Never  => Attribute::NoInline.apply_llfn(Function, val),
+        Never  => {
+            if cx.tcx().sess.target.target.arch != "amdgpu" {
+                Attribute::NoInline.apply_llfn(Function, val);
+            }
+        },
         None   => {
             Attribute::InlineHint.unapply_llfn(Function, val);
             Attribute::AlwaysInline.unapply_llfn(Function, val);
@@ -143,7 +148,7 @@ pub fn from_fn_attrs(
     let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id))
         .unwrap_or(CodegenFnAttrs::new());
 
-    inline(llfn, codegen_fn_attrs.inline);
+    inline(cx, llfn, codegen_fn_attrs.inline);
 
     // The `uwtable` attribute according to LLVM is:
     //
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index cfbc2ab9007..e3526a5a2ee 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -496,6 +496,14 @@ impl Builder<'a, 'll, 'tcx> {
 
 
     pub fn range_metadata(&self, load: &'ll Value, range: Range<u128>) {
+        if self.sess().target.target.arch == "amdgpu" {
+            // amdgpu/LLVM does something weird and thinks a i64 value is
+            // split into a v2i32, halving the bitwidth LLVM expects,
+            // tripping an assertion. So, for now, just disable this
+            // optimization.
+            return;
+        }
+
         unsafe {
             let llty = val_ty(load);
             let v = [
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index 2e90f95fa8e..4b4ccb3b600 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -96,7 +96,7 @@ pub fn get_fn(
         debug!("get_fn: not casting pointer!");
 
         if instance.def.is_inline(tcx) {
-            attributes::inline(llfn, attributes::InlineAttr::Hint);
+            attributes::inline(cx, llfn, attributes::InlineAttr::Hint);
         }
         attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()));
 
diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs
index dd62a12553c..0cb8f99efc3 100644
--- a/src/librustc_codegen_llvm/mir/statement.rs
+++ b/src/librustc_codegen_llvm/mir/statement.rs
@@ -92,7 +92,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
             mir::StatementKind::ReadForMatch(_) |
             mir::StatementKind::EndRegion(_) |
             mir::StatementKind::Validate(..) |
-            mir::StatementKind::UserAssertTy(..) |
+            mir::StatementKind::AscribeUserType(..) |
             mir::StatementKind::Nop => bx,
         }
     }
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index 7f25911abec..a8502e92447 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -180,7 +180,7 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
     debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
     if instance.def.is_inline(cx.tcx) {
-        attributes::inline(lldecl, attributes::InlineAttr::Hint);
+        attributes::inline(cx, lldecl, attributes::InlineAttr::Hint);
     }
     attributes::from_fn_attrs(cx, lldecl, Some(instance.def.def_id()));
 
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 2c32cbdd00f..681cf0d5fc9 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -90,7 +90,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
     macro_rules! add_pre_expansion_builtin {
         ($sess:ident, $($name:ident),*,) => (
             {$(
-                store.register_early_pass($sess, false, box $name);
+                store.register_pre_expansion_pass($sess, box $name);
                 )*}
             )
     }
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 4e24a26983d..7d01ed556c8 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -81,7 +81,7 @@ fn main() {
     let is_crossed = target != host;
 
     let mut optional_components =
-        vec!["x86", "arm", "aarch64", "mips", "powerpc",
+        vec!["x86", "arm", "aarch64", "amdgpu", "mips", "powerpc",
              "systemz", "jsbackend", "webassembly", "msp430", "sparc", "nvptx"];
 
     let mut version_cmd = Command::new(&llvm_config);
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 76f6bcb5e56..60aeb92d91a 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -535,10 +535,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 // flow_state already handled).
             }
             StatementKind::Nop
-            | StatementKind::UserAssertTy(..)
+            | StatementKind::AscribeUserType(..)
             | StatementKind::Validate(..)
             | StatementKind::StorageLive(..) => {
-                // `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
+                // `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
                 // to borrow check.
             }
             StatementKind::StorageDead(local) => {
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 457499ded56..7e8e1b32d4d 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -17,7 +17,7 @@ use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
-use rustc::mir::{Local, Statement, Terminator};
+use rustc::mir::{Statement, Terminator};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid};
@@ -175,10 +175,11 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
         self.super_terminator(block, terminator, location);
     }
 
-    fn visit_user_assert_ty(
+    fn visit_ascribe_user_ty(
         &mut self,
+        _place: &Place<'tcx>,
+        _variance: &ty::Variance,
         _c_ty: &CanonicalTy<'tcx>,
-        _local: &Local,
         _location: Location,
     ) {
     }
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index f233a17597a..71345f22e44 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -144,10 +144,10 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc
             // EndRegion matters to older NLL/MIR AST borrowck, not to alias NLL
             StatementKind::EndRegion(..) |
             StatementKind::Nop |
-            StatementKind::UserAssertTy(..) |
+            StatementKind::AscribeUserType(..) |
             StatementKind::Validate(..) |
             StatementKind::StorageLive(..) => {
-                // `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
+                // `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
                 // to borrow check.
             }
             StatementKind::StorageDead(local) => {
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 cb15c88bb3e..214628600b3 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -319,23 +319,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
 
         for variable in self.definitions.indices() {
+            let scc = self.constraint_sccs.scc(variable);
+
             match self.definitions[variable].origin {
                 NLLRegionVariableOrigin::FreeRegion => {
                     // For each free, universally quantified region X:
 
                     // Add all nodes in the CFG to liveness constraints
-                    let variable_scc = self.constraint_sccs.scc(variable);
                     self.liveness_constraints.add_all_points(variable);
-                    self.scc_values.add_all_points(variable_scc);
+                    self.scc_values.add_all_points(scc);
 
                     // Add `end(X)` into the set for X.
-                    self.add_element_to_scc_of(variable, variable);
+                    self.scc_values.add_element(scc, variable);
                 }
 
                 NLLRegionVariableOrigin::BoundRegion(ui) => {
                     // Each placeholder region X outlives its
-                    // associated universe but nothing else.
-                    self.add_element_to_scc_of(variable, ui);
+                    // associated universe but nothing else. Every
+                    // placeholder region is always in a universe that
+                    // contains `ui` -- but when placeholder regions
+                    // are placed into an SCC, that SCC may include
+                    // things from other universes that do not include
+                    // `ui`.
+                    let scc_universe = self.scc_universes[scc];
+                    if ui.is_subset_of(scc_universe) {
+                        self.scc_values.add_element(scc, ui);
+                    } else {
+                        self.add_incompatible_universe(scc);
+                    }
                 }
 
                 NLLRegionVariableOrigin::Existential => {
@@ -383,13 +394,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         self.scc_universes[scc]
     }
 
-    /// Adds `elem` to the value of the SCC in which `v` appears.
-    fn add_element_to_scc_of(&mut self, v: RegionVid, elem: impl ToElementIndex) {
-        debug!("add_live_element({:?}, {:?})", v, elem);
-        let scc = self.constraint_sccs.scc(v);
-        self.scc_values.add_element(scc, elem);
-    }
-
     /// Perform region inference and report errors if we see any
     /// unsatisfiable constraints. If this is a closure, returns the
     /// region requirements to propagate to our creator, if any.
@@ -516,22 +520,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // merge the bits.
                 self.scc_values.add_region(scc_a, scc_b);
             } else {
-                // Otherwise, the only way for `A` to outlive `B`
-                // is for it to outlive static. This is actually stricter
-                // than necessary: ideally, we'd support bounds like `for<'a: 'b`>`
-                // that might then allow us to approximate `'a` with `'b` and not
-                // `'static`. But it will have to do for now.
-                //
-                // The code here is a bit hacky: we grab the current
-                // value of the SCC in which `'static` appears, but
-                // this value may not be fully computed yet. That's ok
-                // though: it will contain the base liveness values,
-                // which include (a) the static free region element
-                // and (b) all the points in the CFG, so it is "good
-                // enough" to bring it in here for our purposes.
-                let fr_static = self.universal_regions.fr_static;
-                let scc_static = constraint_sccs.scc(fr_static);
-                self.scc_values.add_region(scc_a, scc_static);
+                self.add_incompatible_universe(scc_a);
             }
         }
 
@@ -563,6 +552,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             .all(|u| u.is_subset_of(universe_a))
     }
 
+    /// Extend `scc` so that it can outlive some placeholder region
+    /// from a universe it can't name; at present, the only way for
+    /// this to be true is if `scc` outlives `'static`. This is
+    /// actually stricter than necessary: ideally, we'd support bounds
+    /// like `for<'a: 'b`>` that might then allow us to approximate
+    /// `'a` with `'b` and not `'static`. But it will have to do for
+    /// now.
+    fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
+        let fr_static = self.universal_regions.fr_static;
+        self.scc_values.add_all_points(scc);
+        self.scc_values.add_element(scc, fr_static);
+    }
+
     /// Once regions have been propagated, this method is used to see
     /// whether the "type tests" produced by typeck were satisfied;
     /// type tests encode type-outlives relationships like `T:
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index e1bd8530629..d77863d598f 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -10,7 +10,7 @@
 
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
+use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
@@ -112,8 +112,13 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_closure_substs: substs={:?}", substs);
     }
 
-    fn visit_user_assert_ty(&mut self, _c_ty: &mut CanonicalTy<'tcx>, _local: &mut Local,
-                            _location: Location) {
+    fn visit_ascribe_user_ty(
+        &mut self,
+        _place: &mut Place<'tcx>,
+        _variance: &mut ty::Variance,
+        _c_ty: &mut CanonicalTy<'tcx>,
+        _location: Location,
+    ) {
         // User-assert-ty statements represent types that the user added explicitly.
         // We don't want to erase the regions from these types: rather, we want to
         // add them as constraints at type-check time.
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 82158acc9e6..de96539ec30 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -17,7 +17,9 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
 use borrow_check::nll::facts::AllFacts;
 use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
 use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
-use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
+use borrow_check::nll::type_check::free_region_relations::{
+    CreateResult, UniversalRegionRelations,
+};
 use borrow_check::nll::universal_regions::UniversalRegions;
 use borrow_check::nll::ToRegionVid;
 use dataflow::move_paths::MoveData;
@@ -246,10 +248,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.sanitize_type(constant, constant.ty);
 
         if let Some(user_ty) = constant.user_ty {
-            if let Err(terr) =
-                self.cx
-                    .eq_canonical_type_and_type(user_ty, constant.ty, location.boring())
-            {
+            if let Err(terr) = self.cx.relate_type_and_user_type(
+                constant.ty,
+                ty::Variance::Invariant,
+                user_ty,
+                location.boring(),
+            ) {
                 span_mirbug!(
                     self,
                     constant,
@@ -271,6 +275,25 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
     fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
         self.super_local_decl(local, local_decl);
         self.sanitize_type(local_decl, local_decl.ty);
+
+        if let Some(user_ty) = local_decl.user_ty {
+            if let Err(terr) = self.cx.relate_type_and_user_type(
+                local_decl.ty,
+                ty::Variance::Invariant,
+                user_ty,
+                Locations::All,
+            ) {
+                span_mirbug!(
+                    self,
+                    local,
+                    "bad user type on variable {:?}: {:?} != {:?} ({:?})",
+                    local,
+                    local_decl.ty,
+                    local_decl.user_ty,
+                    terr,
+                );
+            }
+        }
     }
 
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
@@ -850,15 +873,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         )
     }
 
-    fn eq_canonical_type_and_type(
+    fn relate_type_and_user_type(
         &mut self,
-        a: CanonicalTy<'tcx>,
-        b: Ty<'tcx>,
+        a: Ty<'tcx>,
+        v: ty::Variance,
+        b: CanonicalTy<'tcx>,
         locations: Locations,
     ) -> Fallible<()> {
-        relate_tys::eq_canonical_type_and_type(
+        relate_tys::relate_type_and_user_type(
             self.infcx,
             a,
+            v,
             b,
             locations,
             self.borrowck_context.as_mut().map(|x| &mut **x),
@@ -879,8 +904,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 // of lowering. Assignments to other sorts of places *are* interesting
                 // though.
                 let is_temp = if let Place::Local(l) = *place {
-                    l != RETURN_PLACE &&
-                    !mir.local_decls[l].is_user_variable.is_some()
+                    l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
                 } else {
                     false
                 };
@@ -905,9 +929,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 }
 
                 if let Some(user_ty) = self.rvalue_user_ty(rv) {
-                    if let Err(terr) = self.eq_canonical_type_and_type(
-                        user_ty,
+                    if let Err(terr) = self.relate_type_and_user_type(
                         rv_ty,
+                        ty::Variance::Invariant,
+                        user_ty,
                         location.boring(),
                     ) {
                         span_mirbug!(
@@ -955,15 +980,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     );
                 };
             }
-            StatementKind::UserAssertTy(c_ty, local) => {
-                let local_ty = mir.local_decls()[local].ty;
-                if let Err(terr) = self.eq_canonical_type_and_type(c_ty, local_ty, Locations::All) {
+            StatementKind::AscribeUserType(ref place, variance, c_ty) => {
+                let place_ty = place.ty(mir, tcx).to_ty(tcx);
+                if let Err(terr) =
+                    self.relate_type_and_user_type(place_ty, variance, c_ty, Locations::All)
+                {
                     span_mirbug!(
                         self,
                         stmt,
-                        "bad type assert ({:?} = {:?}): {:?}",
+                        "bad type assert ({:?} <: {:?}): {:?}",
+                        place_ty,
                         c_ty,
-                        local_ty,
                         terr
                     );
                 }
@@ -1142,8 +1169,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             Some((ref dest, _target_block)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
                 let is_temp = if let Place::Local(l) = *dest {
-                    l != RETURN_PLACE &&
-                    !mir.local_decls[l].is_user_variable.is_some()
+                    l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
                 } else {
                     false
                 };
@@ -1562,22 +1588,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     /// If this rvalue supports a user-given type annotation, then
     /// extract and return it. This represents the final type of the
     /// rvalue and will be unified with the inferred type.
-    fn rvalue_user_ty(
-        &self,
-        rvalue: &Rvalue<'tcx>,
-    ) -> Option<CanonicalTy<'tcx>> {
+    fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<CanonicalTy<'tcx>> {
         match rvalue {
-            Rvalue::Use(_) |
-            Rvalue::Repeat(..) |
-            Rvalue::Ref(..) |
-            Rvalue::Len(..) |
-            Rvalue::Cast(..) |
-            Rvalue::BinaryOp(..) |
-            Rvalue::CheckedBinaryOp(..) |
-            Rvalue::NullaryOp(..) |
-            Rvalue::UnaryOp(..) |
-            Rvalue::Discriminant(..) =>
-                None,
+            Rvalue::Use(_)
+            | Rvalue::Repeat(..)
+            | Rvalue::Ref(..)
+            | Rvalue::Len(..)
+            | Rvalue::Cast(..)
+            | Rvalue::BinaryOp(..)
+            | Rvalue::CheckedBinaryOp(..)
+            | Rvalue::NullaryOp(..)
+            | Rvalue::UnaryOp(..)
+            | Rvalue::Discriminant(..) => None,
 
             Rvalue::Aggregate(aggregate, _) => match **aggregate {
                 AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
@@ -1585,7 +1607,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 AggregateKind::Tuple => None,
                 AggregateKind::Closure(_, _) => None,
                 AggregateKind::Generator(_, _, _) => None,
-            }
+            },
         }
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
index 8ffce9c9492..06cb44ac971 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
@@ -21,8 +21,8 @@ use rustc::ty::subst::Kind;
 use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::IndexVec;
-use std::mem;
 
+/// Adds sufficient constraints to ensure that `a <: b`.
 pub(super) fn sub_types<'tcx>(
     infcx: &InferCtxt<'_, '_, 'tcx>,
     a: Ty<'tcx>,
@@ -41,6 +41,7 @@ pub(super) fn sub_types<'tcx>(
     Ok(())
 }
 
+/// Adds sufficient constraints to ensure that `a == b`.
 pub(super) fn eq_types<'tcx>(
     infcx: &InferCtxt<'_, '_, 'tcx>,
     a: Ty<'tcx>,
@@ -59,28 +60,38 @@ pub(super) fn eq_types<'tcx>(
     Ok(())
 }
 
-pub(super) fn eq_canonical_type_and_type<'tcx>(
+/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
+/// a user-given type (which means it may have canonical variables
+/// encoding things like `_`).
+pub(super) fn relate_type_and_user_type<'tcx>(
     infcx: &InferCtxt<'_, '_, 'tcx>,
-    a: CanonicalTy<'tcx>,
-    b: Ty<'tcx>,
+    a: Ty<'tcx>,
+    v: ty::Variance,
+    b: CanonicalTy<'tcx>,
     locations: Locations,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
 ) -> Fallible<()> {
     debug!(
-        "eq_canonical_type_and_type(a={:?}, b={:?}, locations={:?})",
+        "sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
         a, b, locations
     );
     let Canonical {
-        variables: a_variables,
-        value: a_value,
-    } = a;
+        variables: b_variables,
+        value: b_value,
+    } = b;
+
+    // The `TypeRelating` code assumes that the "canonical variables"
+    // appear in the "a" side, so flip `Contravariant` ambient
+    // variance to get the right relationship.
+    let v1 = ty::Contravariant.xform(v);
+
     TypeRelating::new(
         infcx,
-        ty::Variance::Invariant,
+        v1,
         locations,
         borrowck_context,
-        a_variables,
-    ).relate(&a_value, &b)?;
+        b_variables,
+    ).relate(&b_value, &a)?;
     Ok(())
 }
 
@@ -128,7 +139,7 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
     /// how can we enforce that? I guess I could add some kind of
     /// "minimum universe constraint" that we can feed to the NLL checker.
     /// --> also, we know this doesn't happen
-    canonical_var_values: IndexVec<CanonicalVar, Option<ScopesAndKind<'tcx>>>,
+    canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
 }
 
 #[derive(Clone, Debug)]
@@ -194,23 +205,44 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
         scope
     }
 
+    /// When we encounter binders during the type traversal, we record
+    /// the value to substitute for each of the things contained in
+    /// that binder. (This will be either a universal placeholder or
+    /// an existential inference variable.) Given the debruijn index
+    /// `debruijn` (and name `br`) of some binder we have now
+    /// encountered, this routine finds the value that we instantiated
+    /// the region with; to do so, it indexes backwards into the list
+    /// of ambient scopes `scopes`.
+    fn lookup_bound_region(
+        debruijn: ty::DebruijnIndex,
+        br: &ty::BoundRegion,
+        first_free_index: ty::DebruijnIndex,
+        scopes: &[BoundRegionScope],
+    ) -> RegionVid {
+        // The debruijn index is a "reverse index" into the
+        // scopes listing. So when we have INNERMOST (0), we
+        // want the *last* scope pushed, and so forth.
+        let debruijn_index = debruijn.index() - first_free_index.index();
+        let scope = &scopes[scopes.len() - debruijn_index - 1];
+
+        // Find this bound region in that scope to map to a
+        // particular region.
+        scope.map[br]
+    }
+
+    /// If `r` is a bound region, find the scope in which it is bound
+    /// (from `scopes`) and return the value that we instantiated it
+    /// with. Otherwise just return `r`.
     fn replace_bound_region(
         &self,
         universal_regions: &UniversalRegions<'tcx>,
         r: ty::Region<'tcx>,
+        first_free_index: ty::DebruijnIndex,
         scopes: &[BoundRegionScope],
     ) -> RegionVid {
         match r {
             ty::ReLateBound(debruijn, br) => {
-                // The debruijn index is a "reverse index" into the
-                // scopes listing. So when we have INNERMOST (0), we
-                // want the *last* scope pushed, and so forth.
-                let debruijn_index = debruijn.index() - ty::INNERMOST.index();
-                let scope = &scopes[scopes.len() - debruijn_index - 1];
-
-                // Find this bound region in that scope to map to a
-                // particular region.
-                scope.map[br]
+                Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
             }
 
             ty::ReVar(v) => *v,
@@ -219,6 +251,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
         }
     }
 
+    /// Push a new outlives requirement into our output set of
+    /// constraints.
     fn push_outlives(&mut self, sup: RegionVid, sub: RegionVid) {
         debug!("push_outlives({:?}: {:?})", sup, sub);
 
@@ -236,46 +270,55 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
         }
     }
 
-    fn equate_var(
+    /// When we encounter a canonical variable `var` in the output,
+    /// equate it with `kind`. If the variable has been previously
+    /// equated, then equate it again.
+    fn relate_var(
         &mut self,
         var: CanonicalVar,
         b_kind: Kind<'tcx>,
     ) -> RelateResult<'tcx, Kind<'tcx>> {
         debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
 
-        // We only encounter canonical variables when equating.
-        assert_eq!(self.ambient_variance, ty::Variance::Invariant);
-
-        // The canonical variable already had a value. Equate that
-        // value with `b`.
-        let old_value = self.canonical_var_values[var].clone();
-        if let Some(ScopesAndKind { scopes, kind }) = old_value {
-            debug!("equate_var: installing kind={:?} scopes={:?}", kind, scopes);
-            let old_a_scopes = mem::replace(&mut self.a_scopes, scopes);
-            let result = self.relate(&kind, &b_kind);
-            self.a_scopes = old_a_scopes;
-            debug!("equate_var: complete, result = {:?}", result);
-            return result;
-        }
+        let generalized_kind = match self.canonical_var_values[var] {
+            Some(v) => v,
+            None => {
+                let generalized_kind = self.generalize_value(b_kind);
+                self.canonical_var_values[var] = Some(generalized_kind);
+                generalized_kind
+            }
+        };
 
-        // Not yet. Capture the value from the RHS and carry on.
-        self.canonical_var_values[var] = Some(ScopesAndKind {
-            scopes: self.b_scopes.clone(),
-            kind: b_kind,
-        });
-        debug!(
-            "equate_var: capturing value {:?}",
-            self.canonical_var_values[var]
-        );
+        // The generalized values we extract from `canonical_var_values` have
+        // been fully instantiated and hence the set of scopes we have
+        // doesn't matter -- just to be sure, put an empty vector
+        // in there.
+        let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
+
+        // Relate the generalized kind to the original one.
+        let result = self.relate(&generalized_kind, &b_kind);
+
+        // Restore the old scopes now.
+        self.a_scopes = old_a_scopes;
+
+        debug!("equate_var: complete, result = {:?}", result);
+        return result;
+    }
 
-        // FIXME -- technically, we should add some sort of
-        // assertion that this value can be named in the universe
-        // of the canonical variable. But in practice these
-        // canonical variables only arise presently in cases where
-        // they are in the root universe and the main typeck has
-        // ensured there are no universe errors. So we just kind
-        // of over look this right now.
-        Ok(b_kind)
+    fn generalize_value(
+        &self,
+        kind: Kind<'tcx>,
+    ) -> Kind<'tcx> {
+        TypeGeneralizer {
+            type_rel: self,
+            first_free_index: ty::INNERMOST,
+            ambient_variance: self.ambient_variance,
+
+            // These always correspond to an `_` or `'_` written by
+            // user, and those are always in the root universe.
+            universe: ty::UniverseIndex::ROOT,
+        }.relate(&kind, &kind)
+            .unwrap()
     }
 }
 
@@ -326,7 +369,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
         // Watch out for the case that we are matching a `?T` against the
         // right-hand side.
         if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
-            self.equate_var(var, b.into())?;
+            self.relate_var(var, b.into())?;
             Ok(a)
         } else {
             debug!(
@@ -348,7 +391,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
         }) = self.borrowck_context
         {
             if let ty::ReCanonical(var) = a {
-                self.equate_var(*var, b.into())?;
+                self.relate_var(*var, b.into())?;
                 return Ok(a);
             }
 
@@ -357,8 +400,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
                 a, b, self.ambient_variance
             );
 
-            let v_a = self.replace_bound_region(universal_regions, a, &self.a_scopes);
-            let v_b = self.replace_bound_region(universal_regions, b, &self.b_scopes);
+            let v_a =
+                self.replace_bound_region(universal_regions, a, ty::INNERMOST, &self.a_scopes);
+            let v_b =
+                self.replace_bound_region(universal_regions, b, ty::INNERMOST, &self.b_scopes);
 
             debug!("regions: v_a = {:?}", v_a);
             debug!("regions: v_b = {:?}", v_b);
@@ -425,19 +470,30 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
             self.b_scopes.push(b_scope);
             self.a_scopes.push(a_scope);
 
-            // FIXME -- to be fully correct, we would set the ambient
-            // variance to Covariant here. As is, we will sometimes
-            // propagate down an ambient variance of Equal -- this in
-            // turn causes us to report errors in some cases where
-            // types perhaps *ought* to be equal. See the
-            // `hr-fn-aau-eq-abu.rs` test for an example. Fixing this
-            // though is a bit nontrivial: in particular, it would
-            // require a more involved handling of canonical
-            // variables, since we would no longer be able to rely on
-            // having an `==` relationship for canonical variables.
+            // Reset the ambient variance to covariant. This is needed
+            // to correctly handle cases like
+            //
+            //     for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
+            //
+            // Somewhat surprisingly, these two types are actually
+            // **equal**, even though the one on the right looks more
+            // polymorphic. The reason is due to subtyping. To see it,
+            // consider that each function can call the other:
+            //
+            // - The left function can call the right with `'b` and
+            //   `'c` both equal to `'a`
+            //
+            // - The right function can call the left with `'a` set to
+            //   `{P}`, where P is the point in the CFG where the call
+            //   itself occurs. Note that `'b` and `'c` must both
+            //   include P. At the point, the call works because of
+            //   subtyping (i.e., `&'b u32 <: &{P} u32`).
+            let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
 
             self.relate(a.skip_binder(), b.skip_binder())?;
 
+            self.ambient_variance = variance;
+
             self.b_scopes.pop().unwrap();
             self.a_scopes.pop().unwrap();
         }
@@ -458,8 +514,17 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
             self.a_scopes.push(a_scope);
             self.b_scopes.push(b_scope);
 
+            // Reset ambient variance to contravariance. See the
+            // covariant case above for an explanation.
+            let variance = ::std::mem::replace(
+                &mut self.ambient_variance,
+                ty::Variance::Contravariant,
+            );
+
             self.relate(a.skip_binder(), b.skip_binder())?;
 
+            self.ambient_variance = variance;
+
             self.b_scopes.pop().unwrap();
             self.a_scopes.pop().unwrap();
         }
@@ -468,7 +533,14 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
     }
 }
 
-struct ScopeInstantiator<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
+/// When we encounter a binder like `for<..> fn(..)`, we actually have
+/// to walk the `fn` value to find all the values bound by the `for`
+/// (these are not explicitly present in the ty representation right
+/// now). This visitor handles that: it descends the type, tracking
+/// binder depth, and finds late-bound regions targeting the
+/// `for<..`>.  For each of those, it creates an entry in
+/// `bound_region_scope`.
+struct ScopeInstantiator<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
     // The debruijn index of the scope we are instantiating.
     target_index: ty::DebruijnIndex,
@@ -510,3 +582,143 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
         false
     }
 }
+
+/// The "type generalize" is used when handling inference variables.
+///
+/// The basic strategy for handling a constraint like `?A <: B` is to
+/// apply a "generalization strategy" to the type `B` -- this replaces
+/// all the lifetimes in the type `B` with fresh inference
+/// variables. (You can read more about the strategy in this [blog
+/// post].)
+///
+/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
+/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
+/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
+/// establishes `'0: 'x` as a constraint.
+///
+/// As a side-effect of this generalization procedure, we also replace
+/// all the bound regions that we have traversed with concrete values,
+/// so that the resulting generalized type is independent from the
+/// scopes.
+///
+/// [blog post]: https://is.gd/0hKvIr
+struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
+    type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
+
+    /// After we generalize this type, we are going to relative it to
+    /// some other type. What will be the variance at this point?
+    ambient_variance: ty::Variance,
+
+    first_free_index: ty::DebruijnIndex,
+
+    universe: ty::UniverseIndex,
+}
+
+impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+        self.type_rel.infcx.tcx
+    }
+
+    fn tag(&self) -> &'static str {
+        "nll::generalizer"
+    }
+
+    fn a_is_expected(&self) -> bool {
+        true
+    }
+
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        variance: ty::Variance,
+        a: &T,
+        b: &T,
+    ) -> RelateResult<'tcx, T> {
+        debug!(
+            "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
+            variance, a, b
+        );
+
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+
+        debug!(
+            "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
+            self.ambient_variance
+        );
+
+        let r = self.relate(a, b)?;
+
+        self.ambient_variance = old_ambient_variance;
+
+        debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
+
+        Ok(r)
+    }
+
+    fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        debug!("TypeGeneralizer::tys(a={:?})", a,);
+
+        match a.sty {
+            ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
+                bug!(
+                    "unexpected inference variable encountered in NLL generalization: {:?}",
+                    a
+                );
+            }
+
+            _ => relate::super_relate_tys(self, a, a),
+        }
+    }
+
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        _: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!("TypeGeneralizer::regions(a={:?})", a,);
+
+        if let ty::ReLateBound(debruijn, _) = a {
+            if *debruijn < self.first_free_index {
+                return Ok(a);
+            }
+        }
+
+        // For now, we just always create a fresh region variable to
+        // replace all the regions in the source type. In the main
+        // type checker, we special case the case where the ambient
+        // variance is `Invariant` and try to avoid creating a fresh
+        // region variable, but since this comes up so much less in
+        // NLL (only when users use `_` etc) it is much less
+        // important.
+        //
+        // As an aside, since these new variables are created in
+        // `self.universe` universe, this also serves to enforce the
+        // universe scoping rules.
+        //
+        // FIXME(#54105) -- if the ambient variance is bivariant,
+        // though, we may however need to check well-formedness or
+        // risk a problem like #41677 again.
+
+        let replacement_region_vid = self.type_rel
+            .infcx
+            .next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
+
+        Ok(replacement_region_vid)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: &ty::Binder<T>,
+        _: &ty::Binder<T>,
+    ) -> RelateResult<'tcx, ty::Binder<T>>
+    where
+        T: Relate<'tcx>,
+    {
+        debug!("TypeGeneralizer::binders(a={:?})", a,);
+
+        self.first_free_index.shift_in(1);
+        let result = self.relate(a.skip_binder(), a.skip_binder())?;
+        self.first_free_index.shift_out(1);
+        Ok(ty::Binder::bind(result))
+    }
+}
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 50d4944d7c2..c4cb7958fd3 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -106,7 +106,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     remainder_scope,
                     init_scope,
                     pattern,
-                    ty,
                     initializer,
                     lint_level
                 } => {
@@ -136,7 +135,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
                                 let scope = (init_scope, source_info);
                                 this.in_scope(scope, lint_level, block, |this| {
-                                    this.expr_into_pattern(block, ty, pattern, init)
+                                    this.expr_into_pattern(block, pattern, init)
                                 })
                             }));
                     } else {
@@ -144,16 +143,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             None, remainder_span, lint_level, slice::from_ref(&pattern),
                             ArmHasGuard(false), None);
 
-                        // FIXME(#47184): We currently only insert `UserAssertTy` statements for
-                        // patterns that are bindings, this is as we do not want to deconstruct
-                        // the type being assertion to match the pattern.
-                        if let PatternKind::Binding { var, .. } = *pattern.kind {
-                            if let Some(ty) = ty {
-                                this.user_assert_ty(block, ty, var, span);
-                            }
-                        }
-
-                        this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| {
+                        this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| {
                             this.storage_live_binding(block, node, span, OutsideGuard);
                             this.schedule_drop_for_binding(node, span, OutsideGuard);
                         })
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 59ebb7703ff..5708ac4e6b5 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -296,6 +296,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let ptr_temp = this.local_decls.push(LocalDecl {
                         mutability: Mutability::Mut,
                         ty: ptr_ty,
+                        user_ty: None,
                         name: None,
                         source_info,
                         visibility_scope: source_info.scope,
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index d3e67ea7b7d..cef1fb77e5c 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -13,16 +13,16 @@
 //! includes the high-level algorithm, the submodules contain the
 //! details.
 
+use build::scope::{CachedBlock, DropKind};
+use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
-use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
-use build::scope::{CachedBlock, DropKind};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::bitvec::BitArray;
-use rustc::ty::{self, Ty};
-use rustc::mir::*;
-use rustc::hir;
 use hair::*;
+use rustc::hir;
+use rustc::mir::*;
+use rustc::ty::{self, CanonicalTy, Ty};
+use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::fx::FxHashMap;
 use syntax::ast::{Name, NodeId};
 use syntax_pos::Span;
 
@@ -37,13 +37,14 @@ mod util;
 pub(crate) struct ArmHasGuard(pub bool);
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
-    pub fn match_expr(&mut self,
-                      destination: &Place<'tcx>,
-                      span: Span,
-                      mut block: BasicBlock,
-                      discriminant: ExprRef<'tcx>,
-                      arms: Vec<Arm<'tcx>>)
-                      -> BlockAnd<()> {
+    pub fn match_expr(
+        &mut self,
+        destination: &Place<'tcx>,
+        span: Span,
+        mut block: BasicBlock,
+        discriminant: ExprRef<'tcx>,
+        arms: Vec<Arm<'tcx>>,
+    ) -> BlockAnd<()> {
         let tcx = self.hir.tcx();
         let discriminant_span = discriminant.span();
         let discriminant_place = unpack!(block = self.as_place(block, discriminant));
@@ -67,7 +68,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let dummy_access = Rvalue::Discriminant(discriminant_place.clone());
         let dummy_ty = dummy_access.ty(&self.local_decls, tcx);
         let dummy_temp = self.temp(dummy_ty, dummy_source_info.span);
-        self.cfg.push_assign(block, dummy_source_info, &dummy_temp, dummy_access);
+        self.cfg
+            .push_assign(block, dummy_source_info, &dummy_temp, dummy_access);
 
         let source_info = self.source_info(discriminant_span);
         let borrowed_input_temp = if tcx.generate_borrow_of_any_match_input() {
@@ -75,38 +77,46 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // inference to find an appropriate one. Therefore you can
             // only use this when NLL is turned on.
             assert!(tcx.use_mir_borrowck());
-            let borrowed_input =
-                Rvalue::Ref(tcx.types.re_empty, BorrowKind::Shared, discriminant_place.clone());
+            let borrowed_input = Rvalue::Ref(
+                tcx.types.re_empty,
+                BorrowKind::Shared,
+                discriminant_place.clone(),
+            );
             let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx);
             let borrowed_input_temp = self.temp(borrowed_input_ty, span);
-            self.cfg.push_assign(block, source_info, &borrowed_input_temp, borrowed_input);
+            self.cfg
+                .push_assign(block, source_info, &borrowed_input_temp, borrowed_input);
             Some(borrowed_input_temp)
         } else {
             None
         };
 
         let mut arm_blocks = ArmBlocks {
-            blocks: arms.iter()
-                        .map(|_| self.cfg.start_new_block())
-                        .collect(),
+            blocks: arms.iter().map(|_| self.cfg.start_new_block()).collect(),
         };
 
         // Get the arm bodies and their scopes, while declaring bindings.
-        let arm_bodies: Vec<_> = arms.iter().map(|arm| {
-            // BUG: use arm lint level
-            let body = self.hir.mirror(arm.body.clone());
-            let scope = self.declare_bindings(None, body.span,
-                                              LintLevel::Inherited,
-                                              &arm.patterns[..],
-                                              ArmHasGuard(arm.guard.is_some()),
-                                              Some((Some(&discriminant_place), discriminant_span)));
-            (body, scope.unwrap_or(self.source_scope))
-        }).collect();
+        let arm_bodies: Vec<_> = arms.iter()
+            .map(|arm| {
+                // BUG: use arm lint level
+                let body = self.hir.mirror(arm.body.clone());
+                let scope = self.declare_bindings(
+                    None,
+                    body.span,
+                    LintLevel::Inherited,
+                    &arm.patterns[..],
+                    ArmHasGuard(arm.guard.is_some()),
+                    Some((Some(&discriminant_place), discriminant_span)),
+                );
+                (body, scope.unwrap_or(self.source_scope))
+            })
+            .collect();
 
         // create binding start block for link them by false edges
         let candidate_count = arms.iter().fold(0, |ac, c| ac + c.patterns.len());
         let pre_binding_blocks: Vec<_> = (0..candidate_count + 1)
-            .map(|_| self.cfg.start_new_block()).collect();
+            .map(|_| self.cfg.start_new_block())
+            .collect();
 
         // assemble a list of candidates: there is one candidate per
         // pattern, which means there may be more than one candidate
@@ -114,21 +124,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // highest priority candidate comes first in the list.
         // (i.e. same order as in source)
 
-        let candidates: Vec<_> =
-            arms.iter()
-                .enumerate()
-                .flat_map(|(arm_index, arm)| {
-                    arm.patterns.iter().enumerate()
-                        .map(move |(pat_index, pat)| {
-                            (arm_index, pat_index, pat, arm.guard.clone())
-                        })
-                })
-                .zip(pre_binding_blocks.iter().zip(pre_binding_blocks.iter().skip(1)))
-                .map(|((arm_index, pat_index, pattern, guard),
-                       (pre_binding_block, next_candidate_pre_binding_block))| {
-
-                    if let (true, Some(borrow_temp)) = (tcx.emit_read_for_match(),
-                                                        borrowed_input_temp.clone()) {
+        let candidates: Vec<_> = arms.iter()
+            .enumerate()
+            .flat_map(|(arm_index, arm)| {
+                arm.patterns
+                    .iter()
+                    .enumerate()
+                    .map(move |(pat_index, pat)| (arm_index, pat_index, pat, arm.guard.clone()))
+            })
+            .zip(
+                pre_binding_blocks
+                    .iter()
+                    .zip(pre_binding_blocks.iter().skip(1)),
+            )
+            .map(
+                |(
+                    (arm_index, pat_index, pattern, guard),
+                    (pre_binding_block, next_candidate_pre_binding_block),
+                )| {
+                    if let (true, Some(borrow_temp)) =
+                        (tcx.emit_read_for_match(), borrowed_input_temp.clone())
+                    {
                         // inject a fake read of the borrowed input at
                         // the start of each arm's pattern testing
                         // code.
@@ -137,10 +153,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         // the variant for an enum while you are in
                         // the midst of matching on it.
                         let pattern_source_info = self.source_info(pattern.span);
-                        self.cfg.push(*pre_binding_block, Statement {
-                            source_info: pattern_source_info,
-                            kind: StatementKind::ReadForMatch(borrow_temp.clone()),
-                        });
+                        self.cfg.push(
+                            *pre_binding_block,
+                            Statement {
+                                source_info: pattern_source_info,
+                                kind: StatementKind::ReadForMatch(borrow_temp.clone()),
+                            },
+                        );
                     }
 
                     // One might ask: why not build up the match pair such that it
@@ -168,18 +187,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         span: pattern.span,
                         match_pairs: vec![MatchPair::new(discriminant_place.clone(), pattern)],
                         bindings: vec![],
+                        ascriptions: vec![],
                         guard,
                         arm_index,
                         pat_index,
                         pre_binding_block: *pre_binding_block,
                         next_candidate_pre_binding_block: *next_candidate_pre_binding_block,
                     }
-                })
-                .collect();
+                },
+            )
+            .collect();
 
         let outer_source_info = self.source_info(span);
-        self.cfg.terminate(*pre_binding_blocks.last().unwrap(),
-                           outer_source_info, TerminatorKind::Unreachable);
+        self.cfg.terminate(
+            *pre_binding_blocks.last().unwrap(),
+            outer_source_info,
+            TerminatorKind::Unreachable,
+        );
 
         // this will generate code to test discriminant_place and
         // branch to the appropriate arm block
@@ -198,7 +222,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             otherwise.sort();
             otherwise.dedup(); // variant switches can introduce duplicate target blocks
             for block in otherwise {
-                self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
+                self.cfg
+                    .terminate(block, source_info, TerminatorKind::Unreachable);
             }
         }
 
@@ -211,50 +236,75 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // Re-enter the source scope we created the bindings in.
             self.source_scope = source_scope;
             unpack!(arm_block = self.into(destination, arm_block, body));
-            self.cfg.terminate(arm_block, outer_source_info,
-                               TerminatorKind::Goto { target: end_block });
+            self.cfg.terminate(
+                arm_block,
+                outer_source_info,
+                TerminatorKind::Goto { target: end_block },
+            );
         }
         self.source_scope = outer_source_info.scope;
 
         end_block.unit()
     }
 
-    pub fn user_assert_ty(&mut self, block: BasicBlock, hir_id: hir::HirId,
-                          var: NodeId, span: Span) {
-        if self.hir.tcx().sess.opts.debugging_opts.disable_nll_user_type_assert { return; }
-
-        let local_id = self.var_local_id(var, OutsideGuard);
-        let source_info = self.source_info(span);
-
-        debug!("user_assert_ty: local_id={:?}", hir_id.local_id);
-        if let Some(c_ty) = self.hir.tables.user_provided_tys().get(hir_id) {
-            debug!("user_assert_ty: c_ty={:?}", c_ty);
-            self.cfg.push(block, Statement {
-                source_info,
-                kind: StatementKind::UserAssertTy(*c_ty, local_id),
-            });
-        }
-    }
-
-    pub fn expr_into_pattern(&mut self,
-                             mut block: BasicBlock,
-                             ty: Option<hir::HirId>,
-                             irrefutable_pat: Pattern<'tcx>,
-                             initializer: ExprRef<'tcx>)
-                             -> BlockAnd<()> {
-        // optimize the case of `let x = ...`
+    pub fn expr_into_pattern(
+        &mut self,
+        mut block: BasicBlock,
+        irrefutable_pat: Pattern<'tcx>,
+        initializer: ExprRef<'tcx>,
+    ) -> BlockAnd<()> {
         match *irrefutable_pat.kind {
-            PatternKind::Binding { mode: BindingMode::ByValue,
-                                   var,
-                                   subpattern: None, .. } => {
-                let place = self.storage_live_binding(block, var, irrefutable_pat.span,
-                                                      OutsideGuard);
-
-                if let Some(ty) = ty {
-                    self.user_assert_ty(block, ty, var, irrefutable_pat.span);
-                }
+            // Optimize the case of `let x = ...` to write directly into `x`
+            PatternKind::Binding {
+                mode: BindingMode::ByValue,
+                var,
+                subpattern: None,
+                ..
+            } => {
+                let place =
+                    self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
+                unpack!(block = self.into(&place, block, initializer));
+                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
+                block.unit()
+            }
 
+            // Optimize the case of `let x: T = ...` to write directly
+            // into `x` and then require that `T == typeof(x)`.
+            //
+            // Weirdly, this is needed to prevent the
+            // `intrinsic-move-val.rs` test case from crashing. That
+            // test works with uninitialized values in a rather
+            // dubious way, so it may be that the test is kind of
+            // broken.
+            PatternKind::AscribeUserType {
+                subpattern: Pattern {
+                    kind: box PatternKind::Binding {
+                        mode: BindingMode::ByValue,
+                        var,
+                        subpattern: None,
+                        ..
+                    },
+                    ..
+                },
+                user_ty: ascription_user_ty,
+            } => {
+                let place =
+                    self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
                 unpack!(block = self.into(&place, block, initializer));
+
+                let source_info = self.source_info(irrefutable_pat.span);
+                self.cfg.push(
+                    block,
+                    Statement {
+                        source_info,
+                        kind: StatementKind::AscribeUserType(
+                            place.clone(),
+                            ty::Variance::Invariant,
+                            ascription_user_ty,
+                        ),
+                    },
+                );
+
                 self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
                 block.unit()
             }
@@ -265,24 +315,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn place_into_pattern(&mut self,
-                               mut block: BasicBlock,
-                               irrefutable_pat: Pattern<'tcx>,
-                               initializer: &Place<'tcx>,
-                               set_match_place: bool)
-                               -> BlockAnd<()> {
+    pub fn place_into_pattern(
+        &mut self,
+        mut block: BasicBlock,
+        irrefutable_pat: Pattern<'tcx>,
+        initializer: &Place<'tcx>,
+        set_match_place: bool,
+    ) -> BlockAnd<()> {
         // create a dummy candidate
         let mut candidate = Candidate {
             span: irrefutable_pat.span,
             match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
             bindings: vec![],
+            ascriptions: vec![],
             guard: None,
 
             // since we don't call `match_candidates`, next fields is unused
             arm_index: 0,
             pat_index: 0,
             pre_binding_block: block,
-            next_candidate_pre_binding_block: block
+            next_candidate_pre_binding_block: block,
         };
 
         // Simplify the candidate. Since the pattern is irrefutable, this should
@@ -290,10 +342,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         unpack!(block = self.simplify_candidate(block, &mut candidate));
 
         if !candidate.match_pairs.is_empty() {
-            span_bug!(candidate.match_pairs[0].pattern.span,
-                      "match pairs {:?} remaining after simplifying \
-                       irrefutable pattern",
-                      candidate.match_pairs);
+            span_bug!(
+                candidate.match_pairs[0].pattern.span,
+                "match pairs {:?} remaining after simplifying \
+                 irrefutable pattern",
+                candidate.match_pairs
+            );
         }
 
         // for matches and function arguments, the place that is being matched
@@ -304,9 +358,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             for binding in &candidate.bindings {
                 let local = self.var_local_id(binding.var_id, OutsideGuard);
 
-                if let Some(ClearCrossCrate::Set(BindingForm::Var(
-                    VarBindingForm {opt_match_place: Some((ref mut match_place, _)), .. }
-                ))) = self.local_decls[local].is_user_variable
+                if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                    opt_match_place: Some((ref mut match_place, _)),
+                    ..
+                }))) = self.local_decls[local].is_user_variable
                 {
                     *match_place = Some(initializer.clone());
                 } else {
@@ -315,6 +370,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         }
 
+        self.ascribe_types(block, &candidate.ascriptions);
+
         // now apply the bindings, which will also declare the variables
         self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
 
@@ -325,116 +382,183 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// scope for the bindings in these patterns, if such a scope had to be
     /// created. NOTE: Declaring the bindings should always be done in their
     /// drop scope.
-    pub fn declare_bindings(&mut self,
-                            mut visibility_scope: Option<SourceScope>,
-                            scope_span: Span,
-                            lint_level: LintLevel,
-                            patterns: &[Pattern<'tcx>],
-                            has_guard: ArmHasGuard,
-                            opt_match_place: Option<(Option<&Place<'tcx>>, Span)>)
-                            -> Option<SourceScope> {
-        assert!(!(visibility_scope.is_some() && lint_level.is_explicit()),
-                "can't have both a visibility and a lint scope at the same time");
+    pub fn declare_bindings(
+        &mut self,
+        mut visibility_scope: Option<SourceScope>,
+        scope_span: Span,
+        lint_level: LintLevel,
+        patterns: &[Pattern<'tcx>],
+        has_guard: ArmHasGuard,
+        opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
+    ) -> Option<SourceScope> {
+        assert!(
+            !(visibility_scope.is_some() && lint_level.is_explicit()),
+            "can't have both a visibility and a lint scope at the same time"
+        );
         let mut scope = self.source_scope;
         let num_patterns = patterns.len();
-        self.visit_bindings(&patterns[0], &mut |this, mutability, name, mode, var, span, ty| {
-            if visibility_scope.is_none() {
-                visibility_scope = Some(this.new_source_scope(scope_span,
-                                                           LintLevel::Inherited,
-                                                           None));
-                // If we have lints, create a new source scope
-                // that marks the lints for the locals. See the comment
-                // on the `source_info` field for why this is needed.
-                if lint_level.is_explicit() {
-                    scope =
-                        this.new_source_scope(scope_span, lint_level, None);
+        self.visit_bindings(
+            &patterns[0],
+            None,
+            &mut |this, mutability, name, mode, var, span, ty, user_ty| {
+                if visibility_scope.is_none() {
+                    visibility_scope =
+                        Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
+                    // If we have lints, create a new source scope
+                    // that marks the lints for the locals. See the comment
+                    // on the `source_info` field for why this is needed.
+                    if lint_level.is_explicit() {
+                        scope = this.new_source_scope(scope_span, lint_level, None);
+                    }
                 }
-            }
-            let source_info = SourceInfo {
-                span,
-                scope,
-            };
-            let visibility_scope = visibility_scope.unwrap();
-            this.declare_binding(source_info, visibility_scope, mutability, name, mode,
-                                 num_patterns, var, ty, has_guard,
-                                 opt_match_place.map(|(x, y)| (x.cloned(), y)),
-                                 patterns[0].span);
-        });
+                let source_info = SourceInfo { span, scope };
+                let visibility_scope = visibility_scope.unwrap();
+                this.declare_binding(
+                    source_info,
+                    visibility_scope,
+                    mutability,
+                    name,
+                    mode,
+                    num_patterns,
+                    var,
+                    ty,
+                    user_ty,
+                    has_guard,
+                    opt_match_place.map(|(x, y)| (x.cloned(), y)),
+                    patterns[0].span,
+                );
+            },
+        );
         visibility_scope
     }
 
-    pub fn storage_live_binding(&mut self,
-                                block: BasicBlock,
-                                var: NodeId,
-                                span: Span,
-                                for_guard: ForGuard)
-                            -> Place<'tcx>
-    {
+    pub fn storage_live_binding(
+        &mut self,
+        block: BasicBlock,
+        var: NodeId,
+        span: Span,
+        for_guard: ForGuard,
+    ) -> Place<'tcx> {
         let local_id = self.var_local_id(var, for_guard);
         let source_info = self.source_info(span);
-        self.cfg.push(block, Statement {
-            source_info,
-            kind: StatementKind::StorageLive(local_id)
-        });
+        self.cfg.push(
+            block,
+            Statement {
+                source_info,
+                kind: StatementKind::StorageLive(local_id),
+            },
+        );
         let place = Place::Local(local_id);
         let var_ty = self.local_decls[local_id].ty;
         let hir_id = self.hir.tcx().hir.node_to_hir_id(var);
         let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id);
-        self.schedule_drop(
-            span, region_scope, &place, var_ty,
-            DropKind::Storage,
-        );
+        self.schedule_drop(span, region_scope, &place, var_ty, DropKind::Storage);
         place
     }
 
-    pub fn schedule_drop_for_binding(&mut self,
-                                     var: NodeId,
-                                     span: Span,
-                                     for_guard: ForGuard) {
+    pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span, for_guard: ForGuard) {
         let local_id = self.var_local_id(var, for_guard);
         let var_ty = self.local_decls[local_id].ty;
         let hir_id = self.hir.tcx().hir.node_to_hir_id(var);
         let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id);
         self.schedule_drop(
-            span, region_scope, &Place::Local(local_id), var_ty,
+            span,
+            region_scope,
+            &Place::Local(local_id),
+            var_ty,
             DropKind::Value {
                 cached_block: CachedBlock::default(),
             },
         );
     }
 
-    pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
-        where F: FnMut(&mut Self, Mutability, Name, BindingMode, NodeId, Span, Ty<'tcx>)
-    {
+    pub fn visit_bindings(
+        &mut self,
+        pattern: &Pattern<'tcx>,
+        mut pattern_user_ty: Option<CanonicalTy<'tcx>>,
+        f: &mut impl FnMut(
+            &mut Self,
+            Mutability,
+            Name,
+            BindingMode,
+            NodeId,
+            Span,
+            Ty<'tcx>,
+            Option<CanonicalTy<'tcx>>,
+        ),
+    ) {
         match *pattern.kind {
-            PatternKind::Binding { mutability, name, mode, var, ty, ref subpattern, .. } => {
-                f(self, mutability, name, mode, var, pattern.span, ty);
+            PatternKind::Binding {
+                mutability,
+                name,
+                mode,
+                var,
+                ty,
+                ref subpattern,
+                ..
+            } => {
+                match mode {
+                    BindingMode::ByValue => { }
+                    BindingMode::ByRef(..) => {
+                        // If this is a `ref` binding (e.g., `let ref
+                        // x: T = ..`), then the type of `x` is not
+                        // `T` but rather `&T`, so ignore
+                        // `pattern_user_ty` for now.
+                        //
+                        // FIXME(#47184): extract or handle `pattern_user_ty` somehow
+                        pattern_user_ty = None;
+                    }
+                }
+
+                f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
                 if let Some(subpattern) = subpattern.as_ref() {
-                    self.visit_bindings(subpattern, f);
+                    self.visit_bindings(subpattern, pattern_user_ty, f);
                 }
             }
-            PatternKind::Array { ref prefix, ref slice, ref suffix } |
-            PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
+            PatternKind::Array {
+                ref prefix,
+                ref slice,
+                ref suffix,
+            }
+            | PatternKind::Slice {
+                ref prefix,
+                ref slice,
+                ref suffix,
+            } => {
+                // FIXME(#47184): extract or handle `pattern_user_ty` somehow
                 for subpattern in prefix.iter().chain(slice).chain(suffix) {
-                    self.visit_bindings(subpattern, f);
+                    self.visit_bindings(subpattern, None, f);
                 }
             }
-            PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
-            }
+            PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
             PatternKind::Deref { ref subpattern } => {
-                self.visit_bindings(subpattern, f);
+                // FIXME(#47184): extract or handle `pattern_user_ty` somehow
+                self.visit_bindings(subpattern, None, f);
             }
-            PatternKind::Leaf { ref subpatterns } |
-            PatternKind::Variant { ref subpatterns, .. } => {
+            PatternKind::AscribeUserType { ref subpattern, user_ty } => {
+                // This corresponds to something like
+                //
+                // ```
+                // let (p1: T1): T2 = ...;
+                // ```
+                //
+                // Not presently possible, though maybe someday.
+                assert!(pattern_user_ty.is_none());
+                self.visit_bindings(subpattern, Some(user_ty), f)
+            }
+            PatternKind::Leaf { ref subpatterns }
+            | PatternKind::Variant {
+                ref subpatterns, ..
+            } => {
+                // FIXME(#47184): extract or handle `pattern_user_ty` somehow
                 for subpattern in subpatterns {
-                    self.visit_bindings(&subpattern.pattern, f);
+                    self.visit_bindings(&subpattern.pattern, None, f);
                 }
             }
         }
     }
 }
 
-
 /// List of blocks for each arm (and potentially other metadata in the
 /// future).
 struct ArmBlocks {
@@ -442,7 +566,7 @@ struct ArmBlocks {
 }
 
 #[derive(Clone, Debug)]
-pub struct Candidate<'pat, 'tcx:'pat> {
+pub struct Candidate<'pat, 'tcx: 'pat> {
     // span of the original pattern that gave rise to this candidate
     span: Span,
 
@@ -452,6 +576,9 @@ pub struct Candidate<'pat, 'tcx:'pat> {
     // ...these bindings established...
     bindings: Vec<Binding<'tcx>>,
 
+    // ...these types asserted...
+    ascriptions: Vec<Ascription<'tcx>>,
+
     // ...and the guard must be evaluated...
     guard: Option<Guard<'tcx>>,
 
@@ -477,8 +604,18 @@ struct Binding<'tcx> {
     binding_mode: BindingMode<'tcx>,
 }
 
+/// Indicates that the type of `source` must be a subtype of the
+/// user-given type `user_ty`; this is basically a no-op but can
+/// influence region inference.
+#[derive(Clone, Debug)]
+struct Ascription<'tcx> {
+    span: Span,
+    source: Place<'tcx>,
+    user_ty: CanonicalTy<'tcx>,
+}
+
 #[derive(Clone, Debug)]
-pub struct MatchPair<'pat, 'tcx:'pat> {
+pub struct MatchPair<'pat, 'tcx: 'pat> {
     // this place...
     place: Place<'tcx>,
 
@@ -490,7 +627,7 @@ pub struct MatchPair<'pat, 'tcx:'pat> {
     // the "rest" part of the pattern right now has type &[T] and
     // as such, it requires an Rvalue::Slice to be generated.
     // See RFC 495 / issue #23121 for the eventual (proper) solution.
-    slice_len_checked: bool
+    slice_len_checked: bool,
 }
 
 #[derive(Clone, Debug, PartialEq)]
@@ -559,15 +696,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// up the list of candidates and recurse with a non-exhaustive
     /// list. This is important to keep the size of the generated code
     /// under control. See `test_candidates` for more details.
-    fn match_candidates<'pat>(&mut self,
-                              span: Span,
-                              arm_blocks: &mut ArmBlocks,
-                              mut candidates: Vec<Candidate<'pat, 'tcx>>,
-                              mut block: BasicBlock)
-                              -> Vec<BasicBlock>
-    {
-        debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
-               span, block, candidates);
+    fn match_candidates<'pat>(
+        &mut self,
+        span: Span,
+        arm_blocks: &mut ArmBlocks,
+        mut candidates: Vec<Candidate<'pat, 'tcx>>,
+        mut block: BasicBlock,
+    ) -> Vec<BasicBlock> {
+        debug!(
+            "matched_candidate(span={:?}, block={:?}, candidates={:?})",
+            span, block, candidates
+        );
 
         // Start by simplifying candidates. Once this process is
         // complete, all the match pairs which remain require some
@@ -580,13 +719,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // whether the higher priority candidates (and hence at
         // the front of the vec) have satisfied all their match
         // pairs.
-        let fully_matched =
-            candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
-        debug!("match_candidates: {:?} candidates fully matched", fully_matched);
+        let fully_matched = candidates
+            .iter()
+            .take_while(|c| c.match_pairs.is_empty())
+            .count();
+        debug!(
+            "match_candidates: {:?} candidates fully matched",
+            fully_matched
+        );
         let mut unmatched_candidates = candidates.split_off(fully_matched);
 
-        let fully_matched_with_guard =
-            candidates.iter().take_while(|c| c.guard.is_some()).count();
+        let fully_matched_with_guard = candidates.iter().take_while(|c| c.guard.is_some()).count();
 
         let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() {
             candidates.split_off(fully_matched_with_guard + 1)
@@ -603,20 +746,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // if None is returned, then any remaining candidates
                 // are unreachable (at least not through this path).
                 // Link them with false edges.
-                debug!("match_candidates: add false edges for unreachable {:?} and unmatched {:?}",
-                       unreachable_candidates, unmatched_candidates);
+                debug!(
+                    "match_candidates: add false edges for unreachable {:?} and unmatched {:?}",
+                    unreachable_candidates, unmatched_candidates
+                );
                 for candidate in unreachable_candidates {
                     let source_info = self.source_info(candidate.span);
                     let target = self.cfg.start_new_block();
-                    if let Some(otherwise) = self.bind_and_guard_matched_candidate(target,
-                                                                                   arm_blocks,
-                                                                                   candidate) {
-                        self.cfg.terminate(otherwise, source_info, TerminatorKind::Unreachable);
+                    if let Some(otherwise) =
+                        self.bind_and_guard_matched_candidate(target, arm_blocks, candidate)
+                    {
+                        self.cfg
+                            .terminate(otherwise, source_info, TerminatorKind::Unreachable);
                     }
                 }
 
                 if unmatched_candidates.is_empty() {
-                    return vec![]
+                    return vec![];
                 } else {
                     let target = self.cfg.start_new_block();
                     return self.match_candidates(span, arm_blocks, unmatched_candidates, target);
@@ -649,11 +795,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         self.match_candidates(span, arm_blocks, untested_candidates, join_block)
     }
 
-    fn join_otherwise_blocks(&mut self,
-                             span: Span,
-                             mut otherwise: Vec<BasicBlock>)
-                             -> BasicBlock
-    {
+    fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec<BasicBlock>) -> BasicBlock {
         let source_info = self.source_info(span);
         otherwise.sort();
         otherwise.dedup(); // variant switches can introduce duplicate target blocks
@@ -662,8 +804,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         } else {
             let join_block = self.cfg.start_new_block();
             for block in otherwise {
-                self.cfg.terminate(block, source_info,
-                                   TerminatorKind::Goto { target: join_block });
+                self.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Goto { target: join_block },
+                );
             }
             join_block
         }
@@ -781,13 +926,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// In addition to avoiding exponential-time blowups, this algorithm
     /// also has nice property that each guard and arm is only generated
     /// once.
-    fn test_candidates<'pat>(&mut self,
-                             span: Span,
-                             arm_blocks: &mut ArmBlocks,
-                             candidates: &[Candidate<'pat, 'tcx>],
-                             block: BasicBlock)
-                             -> (Vec<BasicBlock>, usize)
-    {
+    fn test_candidates<'pat>(
+        &mut self,
+        span: Span,
+        arm_blocks: &mut ArmBlocks,
+        candidates: &[Candidate<'pat, 'tcx>],
+        block: BasicBlock,
+    ) -> (Vec<BasicBlock>, usize) {
         // extract the match-pair from the highest priority candidate
         let match_pair = &candidates.first().unwrap().match_pairs[0];
         let mut test = self.test(match_pair);
@@ -797,34 +942,44 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // may want to add cases based on the candidates that are
         // available
         match test.kind {
-            TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
+            TestKind::SwitchInt {
+                switch_ty,
+                ref mut options,
+                ref mut indices,
+            } => {
                 for candidate in candidates.iter() {
-                    if !self.add_cases_to_switch(&match_pair.place,
-                                                 candidate,
-                                                 switch_ty,
-                                                 options,
-                                                 indices) {
+                    if !self.add_cases_to_switch(
+                        &match_pair.place,
+                        candidate,
+                        switch_ty,
+                        options,
+                        indices,
+                    ) {
                         break;
                     }
                 }
             }
-            TestKind::Switch { adt_def: _, ref mut variants} => {
+            TestKind::Switch {
+                adt_def: _,
+                ref mut variants,
+            } => {
                 for candidate in candidates.iter() {
-                    if !self.add_variants_to_switch(&match_pair.place,
-                                                    candidate,
-                                                    variants) {
+                    if !self.add_variants_to_switch(&match_pair.place, candidate, variants) {
                         break;
                     }
                 }
             }
-            _ => { }
+            _ => {}
         }
 
         // perform the test, branching to one of N blocks. For each of
         // those N possible outcomes, create a (initially empty)
         // vector of candidates. Those are the candidates that still
         // apply if the test has that particular outcome.
-        debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
+        debug!(
+            "match_candidates: test={:?} match_pair={:?}",
+            test, match_pair
+        );
         let target_blocks = self.perform_test(block, &match_pair.place, &test);
         let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();
 
@@ -832,31 +987,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // `target_candidates`. Note that at some point we may
         // encounter a candidate where the test is not relevant; at
         // that point, we stop sorting.
-        let tested_candidates =
-            candidates.iter()
-                      .take_while(|c| self.sort_candidate(&match_pair.place,
-                                                          &test,
-                                                          c,
-                                                          &mut target_candidates))
-                      .count();
+        let tested_candidates = candidates
+            .iter()
+            .take_while(|c| {
+                self.sort_candidate(&match_pair.place, &test, c, &mut target_candidates)
+            })
+            .count();
         assert!(tested_candidates > 0); // at least the last candidate ought to be tested
         debug!("tested_candidates: {}", tested_candidates);
-        debug!("untested_candidates: {}", candidates.len() - tested_candidates);
+        debug!(
+            "untested_candidates: {}",
+            candidates.len() - tested_candidates
+        );
 
         // For each outcome of test, process the candidates that still
         // apply. Collect a list of blocks where control flow will
         // branch if one of the `target_candidate` sets is not
         // exhaustive.
-        let otherwise: Vec<_> =
-            target_blocks.into_iter()
-                         .zip(target_candidates)
-                         .flat_map(|(target_block, target_candidates)| {
-                             self.match_candidates(span,
-                                                   arm_blocks,
-                                                   target_candidates,
-                                                   target_block)
-                         })
-                         .collect();
+        let otherwise: Vec<_> = target_blocks
+            .into_iter()
+            .zip(target_candidates)
+            .flat_map(|(target_block, target_candidates)| {
+                self.match_candidates(span, arm_blocks, target_candidates, target_block)
+            })
+            .collect();
 
         (otherwise, tested_candidates)
     }
@@ -873,30 +1027,41 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// bindings, further tests would be a use-after-move (which would
     /// in turn be detected by the borrowck code that runs on the
     /// MIR).
-    fn bind_and_guard_matched_candidate<'pat>(&mut self,
-                                              mut block: BasicBlock,
-                                              arm_blocks: &mut ArmBlocks,
-                                              candidate: Candidate<'pat, 'tcx>)
-                                              -> Option<BasicBlock> {
-        debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
-               block, candidate);
+    fn bind_and_guard_matched_candidate<'pat>(
+        &mut self,
+        mut block: BasicBlock,
+        arm_blocks: &mut ArmBlocks,
+        candidate: Candidate<'pat, 'tcx>,
+    ) -> Option<BasicBlock> {
+        debug!(
+            "bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
+            block, candidate
+        );
 
         debug_assert!(candidate.match_pairs.is_empty());
 
+        self.ascribe_types(block, &candidate.ascriptions);
+
         let arm_block = arm_blocks.blocks[candidate.arm_index];
         let candidate_source_info = self.source_info(candidate.span);
 
-        self.cfg.terminate(block, candidate_source_info,
-                               TerminatorKind::Goto { target: candidate.pre_binding_block });
+        self.cfg.terminate(
+            block,
+            candidate_source_info,
+            TerminatorKind::Goto {
+                target: candidate.pre_binding_block,
+            },
+        );
 
         block = self.cfg.start_new_block();
-        self.cfg.terminate(candidate.pre_binding_block, candidate_source_info,
-                               TerminatorKind::FalseEdges {
-                                   real_target: block,
-                                   imaginary_targets:
-                                       vec![candidate.next_candidate_pre_binding_block],
-                               });
-
+        self.cfg.terminate(
+            candidate.pre_binding_block,
+            candidate_source_info,
+            TerminatorKind::FalseEdges {
+                real_target: block,
+                imaginary_targets: vec![candidate.next_candidate_pre_binding_block],
+            },
+        );
 
         // rust-lang/rust#27282: The `autoref` business deserves some
         // explanation here.
@@ -980,13 +1145,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         //      match input itself; it is up to us to create a place
         //      holding a `&` or `&mut` that we can then borrow).
 
-        let autoref = self.hir.tcx().all_pat_vars_are_implicit_refs_within_guards();
+        let autoref = self.hir
+            .tcx()
+            .all_pat_vars_are_implicit_refs_within_guards();
         if let Some(guard) = candidate.guard {
             if autoref {
                 self.bind_matched_candidate_for_guard(
-                    block, candidate.pat_index, &candidate.bindings);
+                    block,
+                    candidate.pat_index,
+                    &candidate.bindings,
+                );
                 let guard_frame = GuardFrame {
-                    locals: candidate.bindings.iter()
+                    locals: candidate
+                        .bindings
+                        .iter()
                         .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode))
                         .collect(),
                 };
@@ -1005,7 +1177,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let cond = unpack!(block = self.as_local_operand(block, guard));
             if autoref {
                 let guard_frame = self.guard_context.pop().unwrap();
-                debug!("Exiting guard building context with locals: {:?}", guard_frame);
+                debug!(
+                    "Exiting guard building context with locals: {:?}",
+                    guard_frame
+                );
             }
 
             let false_edge_block = self.cfg.start_new_block();
@@ -1037,45 +1212,82 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             //
             // and that is clearly not correct.
             let post_guard_block = self.cfg.start_new_block();
-            self.cfg.terminate(block, source_info,
-                               TerminatorKind::if_(self.hir.tcx(), cond, post_guard_block,
-                                                   false_edge_block));
+            self.cfg.terminate(
+                block,
+                source_info,
+                TerminatorKind::if_(self.hir.tcx(), cond, post_guard_block, false_edge_block),
+            );
 
             if autoref {
                 self.bind_matched_candidate_for_arm_body(post_guard_block, &candidate.bindings);
             }
 
-            self.cfg.terminate(post_guard_block, source_info,
-                               TerminatorKind::Goto { target: arm_block });
+            self.cfg.terminate(
+                post_guard_block,
+                source_info,
+                TerminatorKind::Goto { target: arm_block },
+            );
 
             let otherwise = self.cfg.start_new_block();
 
-            self.cfg.terminate(false_edge_block, source_info,
-                               TerminatorKind::FalseEdges {
-                                   real_target: otherwise,
-                                   imaginary_targets:
-                                       vec![candidate.next_candidate_pre_binding_block],
-                               });
+            self.cfg.terminate(
+                false_edge_block,
+                source_info,
+                TerminatorKind::FalseEdges {
+                    real_target: otherwise,
+                    imaginary_targets: vec![candidate.next_candidate_pre_binding_block],
+                },
+            );
             Some(otherwise)
         } else {
             // (Here, it is not too early to bind the matched
             // candidate on `block`, because there is no guard result
             // that we have to inspect before we bind them.)
             self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
-            self.cfg.terminate(block, candidate_source_info,
-                               TerminatorKind::Goto { target: arm_block });
+            self.cfg.terminate(
+                block,
+                candidate_source_info,
+                TerminatorKind::Goto { target: arm_block },
+            );
             None
         }
     }
 
+    /// Append `AscribeUserType` statements onto the end of `block`
+    /// for each ascription
+    fn ascribe_types<'pat>(
+        &mut self,
+        block: BasicBlock,
+        ascriptions: &[Ascription<'tcx>],
+    ) {
+        for ascription in ascriptions {
+            let source_info = self.source_info(ascription.span);
+            self.cfg.push(
+                block,
+                Statement {
+                    source_info,
+                    kind: StatementKind::AscribeUserType(
+                        ascription.source.clone(),
+                        ty::Variance::Covariant,
+                        ascription.user_ty,
+                    ),
+                },
+            );
+        }
+    }
+
     // Only called when all_pat_vars_are_implicit_refs_within_guards,
     // and thus all code/comments assume we are in that context.
-    fn bind_matched_candidate_for_guard(&mut self,
-                                        block: BasicBlock,
-                                        pat_index: usize,
-                                        bindings: &[Binding<'tcx>]) {
-        debug!("bind_matched_candidate_for_guard(block={:?}, pat_index={:?}, bindings={:?})",
-               block, pat_index, bindings);
+    fn bind_matched_candidate_for_guard(
+        &mut self,
+        block: BasicBlock,
+        pat_index: usize,
+        bindings: &[Binding<'tcx>],
+    ) {
+        debug!(
+            "bind_matched_candidate_for_guard(block={:?}, pat_index={:?}, bindings={:?})",
+            block, pat_index, bindings
+        );
 
         // Assign each of the bindings. Since we are binding for a
         // guard expression, this will never trigger moves out of the
@@ -1088,8 +1300,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // a reference R: &T pointing to the location matched by
             // the pattern, and every occurrence of P within a guard
             // denotes *R.
-            let ref_for_guard = self.storage_live_binding(
-                block, binding.var_id, binding.span, RefWithinGuard);
+            let ref_for_guard =
+                self.storage_live_binding(block, binding.var_id, binding.span, RefWithinGuard);
             // Question: Why schedule drops if bindings are all
             // shared-&'s?  Answer: Because schedule_drop_for_binding
             // also emits StorageDead's for those locals.
@@ -1097,7 +1309,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             match binding.binding_mode {
                 BindingMode::ByValue => {
                     let rvalue = Rvalue::Ref(re_empty, BorrowKind::Shared, binding.source.clone());
-                    self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
+                    self.cfg
+                        .push_assign(block, source_info, &ref_for_guard, rvalue);
                 }
                 BindingMode::ByRef(region, borrow_kind) => {
                     // Tricky business: For `ref id` and `ref mut id`
@@ -1114,9 +1327,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     // used by the arm body itself. This eases
                     // observing two-phase borrow restrictions.
                     let val_for_guard = self.storage_live_binding(
-                        block, binding.var_id, binding.span, ValWithinGuard(pat_index));
+                        block,
+                        binding.var_id,
+                        binding.span,
+                        ValWithinGuard(pat_index),
+                    );
                     self.schedule_drop_for_binding(
-                        binding.var_id, binding.span, ValWithinGuard(pat_index));
+                        binding.var_id,
+                        binding.span,
+                        ValWithinGuard(pat_index),
+                    );
 
                     // rust-lang/rust#27282: We reuse the two-phase
                     // borrow infrastructure so that the mutable
@@ -1126,27 +1346,36 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     // discussion on rust-lang/rust#49870.
                     let borrow_kind = match borrow_kind {
                         BorrowKind::Shared | BorrowKind::Unique => borrow_kind,
-                        BorrowKind::Mut { .. } => BorrowKind::Mut { allow_two_phase_borrow: true },
+                        BorrowKind::Mut { .. } => BorrowKind::Mut {
+                            allow_two_phase_borrow: true,
+                        },
                     };
                     let rvalue = Rvalue::Ref(region, borrow_kind, binding.source.clone());
-                    self.cfg.push_assign(block, source_info, &val_for_guard, rvalue);
+                    self.cfg
+                        .push_assign(block, source_info, &val_for_guard, rvalue);
                     let rvalue = Rvalue::Ref(region, BorrowKind::Shared, val_for_guard);
-                    self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
+                    self.cfg
+                        .push_assign(block, source_info, &ref_for_guard, rvalue);
                 }
             }
         }
     }
 
-    fn bind_matched_candidate_for_arm_body(&mut self,
-                                           block: BasicBlock,
-                                           bindings: &[Binding<'tcx>]) {
-        debug!("bind_matched_candidate_for_arm_body(block={:?}, bindings={:?}", block, bindings);
+    fn bind_matched_candidate_for_arm_body(
+        &mut self,
+        block: BasicBlock,
+        bindings: &[Binding<'tcx>],
+    ) {
+        debug!(
+            "bind_matched_candidate_for_arm_body(block={:?}, bindings={:?}",
+            block, bindings
+        );
 
         // Assign each of the bindings. This may trigger moves out of the candidate.
         for binding in bindings {
             let source_info = self.source_info(binding.span);
-            let local = self.storage_live_binding(block, binding.var_id, binding.span,
-                                                  OutsideGuard);
+            let local =
+                self.storage_live_binding(block, binding.var_id, binding.span, OutsideGuard);
             self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
             let rvalue = match binding.binding_mode {
                 BindingMode::ByValue => {
@@ -1175,22 +1404,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// parts of the matched data, and we want them to be distinct
     /// temps in order to simplify checks performed by our internal
     /// leveraging of two-phase borrows).
-    fn declare_binding(&mut self,
-                       source_info: SourceInfo,
-                       visibility_scope: SourceScope,
-                       mutability: Mutability,
-                       name: Name,
-                       mode: BindingMode,
-                       num_patterns: usize,
-                       var_id: NodeId,
-                       var_ty: Ty<'tcx>,
-                       has_guard: ArmHasGuard,
-                       opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
-                       pat_span: Span)
-    {
-        debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
-                visibility_scope={:?}, source_info={:?})",
-               var_id, name, mode, var_ty, visibility_scope, source_info);
+    fn declare_binding(
+        &mut self,
+        source_info: SourceInfo,
+        visibility_scope: SourceScope,
+        mutability: Mutability,
+        name: Name,
+        mode: BindingMode,
+        num_patterns: usize,
+        var_id: NodeId,
+        var_ty: Ty<'tcx>,
+        user_var_ty: Option<CanonicalTy<'tcx>>,
+        has_guard: ArmHasGuard,
+        opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
+        pat_span: Span,
+    ) {
+        debug!(
+            "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
+             visibility_scope={:?}, source_info={:?})",
+            var_id, name, mode, var_ty, visibility_scope, source_info
+        );
 
         let tcx = self.hir.tcx();
         let binding_mode = match mode {
@@ -1199,7 +1432,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         };
         let local = LocalDecl::<'tcx> {
             mutability,
-            ty: var_ty.clone(),
+            ty: var_ty,
+            user_ty: user_var_ty,
             name: Some(name),
             source_info,
             visibility_scope,
@@ -1231,6 +1465,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // See previous comment.
                 mutability: Mutability::Not,
                 ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty),
+                user_ty: None,
                 name: Some(name),
                 source_info,
                 visibility_scope,
@@ -1238,7 +1473,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 internal: false,
                 is_user_variable: Some(ClearCrossCrate::Set(BindingForm::RefForGuard)),
             });
-            LocalsForNode::ForGuard { vals_for_guard, ref_for_guard, for_arm_body }
+            LocalsForNode::ForGuard {
+                vals_for_guard,
+                ref_for_guard,
+                for_arm_body,
+            }
         } else {
             LocalsForNode::One(for_arm_body)
         };
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 147b8cc2175..14da8e90838 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -23,7 +23,7 @@
 //! testing a value against a constant.
 
 use build::{BlockAnd, BlockAndExtension, Builder};
-use build::matches::{Binding, MatchPair, Candidate};
+use build::matches::{Ascription, Binding, MatchPair, Candidate};
 use hair::*;
 use rustc::mir::*;
 
@@ -63,6 +63,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                  candidate: &mut Candidate<'pat, 'tcx>)
                                  -> Result<(), MatchPair<'pat, 'tcx>> {
         match *match_pair.pattern.kind {
+            PatternKind::AscribeUserType { ref subpattern, user_ty } => {
+                candidate.ascriptions.push(Ascription {
+                    span: match_pair.pattern.span,
+                    user_ty,
+                    source: match_pair.place.clone(),
+                });
+
+                candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+
+                Ok(())
+            }
+
             PatternKind::Wild => {
                 // nothing left to do
                 Ok(())
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 4a0b4b0c885..373c8e039f8 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -70,13 +70,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
 
-            PatternKind::Range { lo, hi, end } => {
+            PatternKind::Range { lo, hi, ty, end } => {
+                assert!(ty == match_pair.pattern.ty);
                 Test {
                     span: match_pair.pattern.span,
                     kind: TestKind::Range {
                         lo,
                         hi,
-                        ty: match_pair.pattern.ty.clone(),
+                        ty,
                         end,
                     },
                 }
@@ -96,6 +97,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
 
+            PatternKind::AscribeUserType { .. } |
             PatternKind::Array { .. } |
             PatternKind::Slice { .. } |
             PatternKind::Wild |
@@ -138,6 +140,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             PatternKind::Array { .. } |
             PatternKind::Wild |
             PatternKind::Binding { .. } |
+            PatternKind::AscribeUserType { .. } |
             PatternKind::Leaf { .. } |
             PatternKind::Deref { .. } => {
                 // don't know how to add these patterns to a switch
@@ -638,6 +641,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             span: candidate.span,
             match_pairs: other_match_pairs,
             bindings: candidate.bindings.clone(),
+            ascriptions: candidate.ascriptions.clone(),
             guard: candidate.guard.clone(),
             arm_index: candidate.arm_index,
             pat_index: candidate.pat_index,
@@ -702,6 +706,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             span: candidate.span,
             match_pairs: all_match_pairs,
             bindings: candidate.bindings.clone(),
+            ascriptions: candidate.ascriptions.clone(),
             guard: candidate.guard.clone(),
             arm_index: candidate.arm_index,
             pat_index: candidate.pat_index,
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 322a6977bed..576c91a02b0 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -730,6 +730,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             self.local_decls.push(LocalDecl {
                 mutability: Mutability::Mut,
                 ty,
+                user_ty: None,
                 source_info,
                 visibility_scope: source_info.scope,
                 name,
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index f42612b4b7a..cc92cdecc60 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -338,7 +338,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
             mir::StatementKind::SetDiscriminant { .. } |
             mir::StatementKind::StorageLive(..) |
             mir::StatementKind::Validate(..) |
-            mir::StatementKind::UserAssertTy(..) |
+            mir::StatementKind::AscribeUserType(..) |
             mir::StatementKind::Nop => {}
 
         }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index dde2e819fd2..5451d27082d 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -304,7 +304,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
             }
             StatementKind::EndRegion(_) |
             StatementKind::Validate(..) |
-            StatementKind::UserAssertTy(..) |
+            StatementKind::AscribeUserType(..) |
             StatementKind::Nop => {}
         }
     }
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 6c8b5d97b6f..85a9734a601 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -76,14 +76,26 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             first_statement_index: region::FirstStatementIndex::new(index),
                         });
 
-                        let ty = local.ty.clone().map(|ty| ty.hir_id);
-                        let pattern = cx.pattern_from_hir(&local.pat);
+                        let mut pattern = cx.pattern_from_hir(&local.pat);
+
+                        if let Some(ty) = &local.ty {
+                            if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
+                                pattern = Pattern {
+                                    ty: pattern.ty,
+                                    span: pattern.span,
+                                    kind: Box::new(PatternKind::AscribeUserType {
+                                        user_ty: *user_ty,
+                                        subpattern: pattern
+                                    })
+                                };
+                            }
+                        }
+
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_scope,
                                 init_scope: region::Scope::Node(hir_id.local_id),
                                 pattern,
-                                ty,
                                 initializer: local.init.to_ref(),
                                 lint_level: cx.lint_level_of(local.id),
                             },
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 2ddb810f491..d86aee54312 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -93,12 +93,11 @@ pub enum StmtKind<'tcx> {
         /// lifetime of temporaries
         init_scope: region::Scope,
 
-        /// let <PAT>: ty = ...
+        /// `let <PAT> = ...`
+        ///
+        /// if a type is included, it is added as an ascription pattern
         pattern: Pattern<'tcx>,
 
-        /// let pat: <TY> = init ...
-        ty: Option<hir::HirId>,
-
         /// let pat: ty = <INIT> ...
         initializer: Option<ExprRef<'tcx>>,
 
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index d7fbbc88cc1..aa1c6902dce 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -416,7 +416,7 @@ pub enum Constructor<'tcx> {
     /// Literal values.
     ConstantValue(&'tcx ty::Const<'tcx>),
     /// Ranges of literal values (`2...5` and `2..5`).
-    ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+    ConstantRange(u128, u128, Ty<'tcx>, RangeEnd),
     /// Array patterns of length n.
     Slice(u64),
 }
@@ -588,7 +588,12 @@ impl<'tcx> Witness<'tcx> {
                 _ => {
                     match *ctor {
                         ConstantValue(value) => PatternKind::Constant { value },
-                        ConstantRange(lo, hi, end) => PatternKind::Range { lo, hi, end },
+                        ConstantRange(lo, hi, ty, end) => PatternKind::Range {
+                            lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
+                            hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
+                            ty,
+                            end,
+                        },
                         _ => PatternKind::Wild,
                     }
                 }
@@ -648,14 +653,18 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                 .collect()
         }
         ty::Char if exhaustive_integer_patterns => {
-            let endpoint = |c: char| {
-                let ty = ty::ParamEnv::empty().and(cx.tcx.types.char);
-                ty::Const::from_bits(cx.tcx, c as u128, ty)
-            };
             vec![
                 // The valid Unicode Scalar Value ranges.
-                ConstantRange(endpoint('\u{0000}'), endpoint('\u{D7FF}'), RangeEnd::Included),
-                ConstantRange(endpoint('\u{E000}'), endpoint('\u{10FFFF}'), RangeEnd::Included),
+                ConstantRange('\u{0000}' as u128,
+                              '\u{D7FF}' as u128,
+                              cx.tcx.types.char,
+                              RangeEnd::Included
+                ),
+                ConstantRange('\u{E000}' as u128,
+                              '\u{10FFFF}' as u128,
+                              cx.tcx.types.char,
+                              RangeEnd::Included
+                ),
             ]
         }
         ty::Int(ity) if exhaustive_integer_patterns => {
@@ -663,19 +672,13 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             let bits = Integer::from_attr(cx.tcx, SignedInt(ity)).size().bits() as u128;
             let min = 1u128 << (bits - 1);
             let max = (1u128 << (bits - 1)) - 1;
-            let ty = ty::ParamEnv::empty().and(pcx.ty);
-            vec![ConstantRange(ty::Const::from_bits(cx.tcx, min as u128, ty),
-                               ty::Const::from_bits(cx.tcx, max as u128, ty),
-                               RangeEnd::Included)]
+            vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included)]
         }
         ty::Uint(uty) if exhaustive_integer_patterns => {
             // FIXME(49937): refactor these bit manipulations into interpret.
             let bits = Integer::from_attr(cx.tcx, UnsignedInt(uty)).size().bits() as u128;
             let max = !0u128 >> (128 - bits);
-            let ty = ty::ParamEnv::empty().and(pcx.ty);
-            vec![ConstantRange(ty::Const::from_bits(cx.tcx, 0, ty),
-                               ty::Const::from_bits(cx.tcx, max, ty),
-                               RangeEnd::Included)]
+            vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included)]
         }
         _ => {
             if cx.is_uninhabited(pcx.ty) {
@@ -811,26 +814,18 @@ impl<'tcx> IntRange<'tcx> {
                  ctor: &Constructor<'tcx>)
                  -> Option<IntRange<'tcx>> {
         match ctor {
-            ConstantRange(lo, hi, end) => {
-                assert_eq!(lo.ty, hi.ty);
-                let ty = lo.ty;
-                let env_ty = ty::ParamEnv::empty().and(ty);
-                if let Some(lo) = lo.assert_bits(tcx, env_ty) {
-                    if let Some(hi) = hi.assert_bits(tcx, env_ty) {
-                        // Perform a shift if the underlying types are signed,
-                        // which makes the interval arithmetic simpler.
-                        let bias = IntRange::signed_bias(tcx, ty);
-                        let (lo, hi) = (lo ^ bias, hi ^ bias);
-                        // Make sure the interval is well-formed.
-                        return if lo > hi || lo == hi && *end == RangeEnd::Excluded {
-                            None
-                        } else {
-                            let offset = (*end == RangeEnd::Excluded) as u128;
-                            Some(IntRange { range: lo..=(hi - offset), ty })
-                        };
-                    }
+            ConstantRange(lo, hi, ty, end) => {
+                // Perform a shift if the underlying types are signed,
+                // which makes the interval arithmetic simpler.
+                let bias = IntRange::signed_bias(tcx, ty);
+                let (lo, hi) = (lo ^ bias, hi ^ bias);
+                // Make sure the interval is well-formed.
+                if lo > hi || lo == hi && *end == RangeEnd::Excluded {
+                    None
+                } else {
+                    let offset = (*end == RangeEnd::Excluded) as u128;
+                    Some(IntRange { range: lo..=(hi - offset), ty })
                 }
-                None
             }
             ConstantValue(val) => {
                 let ty = val.ty;
@@ -853,7 +848,12 @@ impl<'tcx> IntRange<'tcx> {
                 -> Option<IntRange<'tcx>> {
         Self::from_ctor(tcx, &match pat.kind {
             box PatternKind::Constant { value } => ConstantValue(value),
-            box PatternKind::Range { lo, hi, end } => ConstantRange(lo, hi, end),
+            box PatternKind::Range { lo, hi, ty, end } => ConstantRange(
+                lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
+                hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
+                ty,
+                end,
+            ),
             _ => return None,
         })
     }
@@ -876,14 +876,12 @@ impl<'tcx> IntRange<'tcx> {
         r: RangeInclusive<u128>,
     ) -> Constructor<'tcx> {
         let bias = IntRange::signed_bias(tcx, ty);
-        let ty = ty::ParamEnv::empty().and(ty);
         let (lo, hi) = r.into_inner();
         if lo == hi {
+            let ty = ty::ParamEnv::empty().and(ty);
             ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty))
         } else {
-            ConstantRange(ty::Const::from_bits(tcx, lo ^ bias, ty),
-                          ty::Const::from_bits(tcx, hi ^ bias, ty),
-                          RangeEnd::Included)
+            ConstantRange(lo ^ bias, hi ^ bias, ty, RangeEnd::Included)
         }
     }
 
@@ -1228,20 +1226,28 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
 /// Slice patterns, however, can match slices of different lengths. For instance,
 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
 ///
-/// Returns `None` in case of a catch-all, which can't be specialized.
-fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
+/// Returns None in case of a catch-all, which can't be specialized.
+fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
                           pat: &Pattern<'tcx>,
                           pcx: PatternContext)
                           -> Option<Vec<Constructor<'tcx>>>
 {
     match *pat.kind {
+        PatternKind::AscribeUserType { ref subpattern, .. } =>
+            pat_constructors(cx, subpattern, pcx),
         PatternKind::Binding { .. } | PatternKind::Wild => None,
         PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]),
         PatternKind::Variant { adt_def, variant_index, .. } => {
             Some(vec![Variant(adt_def.variants[variant_index].did)])
         }
         PatternKind::Constant { value } => Some(vec![ConstantValue(value)]),
-        PatternKind::Range { lo, hi, end } => Some(vec![ConstantRange(lo, hi, end)]),
+        PatternKind::Range { lo, hi, ty, end } =>
+            Some(vec![ConstantRange(
+                lo.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
+                hi.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
+                ty,
+                end,
+            )]),
         PatternKind::Array { .. } => match pcx.ty.sty {
             ty::Array(_, length) => Some(vec![
                 Slice(length.unwrap_usize(cx.tcx))
@@ -1381,10 +1387,13 @@ fn slice_pat_covered_by_constructor<'tcx>(
 // constructor is a range or constant with an integer type.
 fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Constructor<'tcx>) -> bool {
     if tcx.features().exhaustive_integer_patterns {
-        if let ConstantValue(value) | ConstantRange(value, _, _) = ctor {
-            if let ty::Char | ty::Int(_) | ty::Uint(_) = value.ty.sty {
-                return true;
-            }
+        let ty = match ctor {
+            ConstantValue(value) => value.ty,
+            ConstantRange(_, _, ty, _) => ty,
+            _ => return false,
+        };
+        if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.sty {
+            return true;
         }
     }
     false
@@ -1535,7 +1544,7 @@ fn constructor_covered_by_range<'a, 'tcx>(
 ) -> Result<bool, ErrorReported> {
     let (from, to, end, ty) = match pat.kind {
         box PatternKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
-        box PatternKind::Range { lo, hi, end } => (lo, hi, end, lo.ty),
+        box PatternKind::Range { lo, hi, ty, end } => (lo, hi, end, ty),
         _ => bug!("`constructor_covered_by_range` called with {:?}", pat),
     };
     trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
@@ -1557,17 +1566,33 @@ fn constructor_covered_by_range<'a, 'tcx>(
                       (end == RangeEnd::Included && to == Ordering::Equal);
             Ok(some_or_ok!(cmp_from(value)) && end)
         },
-        ConstantRange(from, to, RangeEnd::Included) => {
-            let to = some_or_ok!(cmp_to(to));
+        ConstantRange(from, to, ty, RangeEnd::Included) => {
+            let to = some_or_ok!(cmp_to(ty::Const::from_bits(
+                tcx,
+                to,
+                ty::ParamEnv::empty().and(ty),
+            )));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(from)) && end)
+            Ok(some_or_ok!(cmp_from(ty::Const::from_bits(
+                tcx,
+                from,
+                ty::ParamEnv::empty().and(ty),
+            ))) && end)
         },
-        ConstantRange(from, to, RangeEnd::Excluded) => {
-            let to = some_or_ok!(cmp_to(to));
+        ConstantRange(from, to, ty, RangeEnd::Excluded) => {
+            let to = some_or_ok!(cmp_to(ty::Const::from_bits(
+                tcx,
+                to,
+                ty::ParamEnv::empty().and(ty)
+            )));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Excluded && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(from)) && end)
+            Ok(some_or_ok!(cmp_from(ty::Const::from_bits(
+                tcx,
+                from,
+                ty::ParamEnv::empty().and(ty)))
+            ) && end)
         }
         Single => Ok(true),
         _ => bug!(),
@@ -1606,6 +1631,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
     let pat = &r[0];
 
     let head: Option<Vec<&Pattern>> = match *pat.kind {
+        PatternKind::AscribeUserType { ref subpattern, .. } =>
+            specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns),
+
         PatternKind::Binding { .. } | PatternKind::Wild => {
             Some(wild_patterns.to_owned())
         }
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 384ee0079dc..ee50322fbb3 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -20,7 +20,7 @@ use interpret::{const_field, const_variant_index};
 
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
 use rustc::hir::def::{Def, CtorKind};
@@ -66,6 +66,11 @@ pub struct Pattern<'tcx> {
 pub enum PatternKind<'tcx> {
     Wild,
 
+    AscribeUserType {
+        user_ty: CanonicalTy<'tcx>,
+        subpattern: Pattern<'tcx>,
+    },
+
     /// x, ref x, x @ P, etc
     Binding {
         mutability: Mutability,
@@ -101,6 +106,7 @@ pub enum PatternKind<'tcx> {
     Range {
         lo: &'tcx ty::Const<'tcx>,
         hi: &'tcx ty::Const<'tcx>,
+        ty: Ty<'tcx>,
         end: RangeEnd,
     },
 
@@ -125,6 +131,8 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self.kind {
             PatternKind::Wild => write!(f, "_"),
+            PatternKind::AscribeUserType { ref subpattern, .. } =>
+                write!(f, "{}: _", subpattern),
             PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => {
                 let is_mut = match mode {
                     BindingMode::ByValue => mutability == Mutability::Mut,
@@ -230,7 +238,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
             PatternKind::Constant { value } => {
                 fmt_const_val(f, value)
             }
-            PatternKind::Range { lo, hi, end } => {
+            PatternKind::Range { lo, hi, ty: _, end } => {
                 fmt_const_val(f, lo)?;
                 match end {
                     RangeEnd::Included => write!(f, "..=")?,
@@ -359,7 +367,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                         );
                         match (end, cmp) {
                             (RangeEnd::Excluded, Some(Ordering::Less)) =>
-                                PatternKind::Range { lo, hi, end },
+                                PatternKind::Range { lo, hi, ty, end },
                             (RangeEnd::Excluded, _) => {
                                 span_err!(
                                     self.tcx.sess,
@@ -373,7 +381,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                                 PatternKind::Constant { value: lo }
                             }
                             (RangeEnd::Included, Some(Ordering::Less)) => {
-                                PatternKind::Range { lo, hi, end }
+                                PatternKind::Range { lo, hi, ty, end }
                             }
                             (RangeEnd::Included, _) => {
                                 let mut err = struct_span_err!(
@@ -939,7 +947,7 @@ macro_rules! CloneImpls {
 CloneImpls!{ <'tcx>
     Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
-    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx>
 }
 
 impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
@@ -973,6 +981,13 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             PatternKind::Wild => PatternKind::Wild,
+            PatternKind::AscribeUserType {
+                ref subpattern,
+                user_ty,
+            } => PatternKind::AscribeUserType {
+                subpattern: subpattern.fold_with(folder),
+                user_ty: user_ty.fold_with(folder),
+            },
             PatternKind::Binding {
                 mutability,
                 name,
@@ -1017,10 +1032,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
             PatternKind::Range {
                 lo,
                 hi,
+                ty,
                 end,
             } => PatternKind::Range {
                 lo: lo.fold_with(folder),
                 hi: hi.fold_with(folder),
+                ty: ty.fold_with(folder),
                 end,
             },
             PatternKind::Slice {
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 545333e8791..cb8e1284d09 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -159,7 +159,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
 
             EndRegion(..) => {}
-            UserAssertTy(..) => {}
+            AscribeUserType(..) => {}
 
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index d4024981c37..f2c011ccee6 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -39,6 +39,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(if_while_or_patterns)]
 #![feature(try_from)]
 #![feature(reverse_bits)]
+#![feature(underscore_imports)]
 
 #![recursion_limit="256"]
 
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 7e7e7cfade6..a6c03975685 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -140,7 +140,9 @@ enum CallKind {
 fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
     let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span };
     LocalDecl {
-        mutability, ty, name: None,
+        mutability, ty,
+        user_ty: None,
+        name: None,
         source_info,
         visibility_scope: source_info.scope,
         internal: false,
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index ec7fd371a44..6fbc2f85c08 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -114,7 +114,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             StatementKind::StorageDead(..) |
             StatementKind::EndRegion(..) |
             StatementKind::Validate(..) |
-            StatementKind::UserAssertTy(..) |
+            StatementKind::AscribeUserType(..) |
             StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
             }
diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index 256b1fd66e9..9edb1a1f76a 100644
--- a/src/librustc_mir/transform/cleanup_post_borrowck.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -12,7 +12,7 @@
 //!
 //!   - `CleanEndRegions`, that reduces the set of `EndRegion` statements
 //!     in the MIR.
-//!   - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements
+//!   - `CleanAscribeUserType`, that replaces all `AscribeUserType` statements
 //!     with `Nop`.
 //!
 //! The `CleanEndRegions` "pass" is actually implemented as two
@@ -24,10 +24,10 @@
 //! MIR and removes any `EndRegion` that is applied to a region that
 //! was not seen in the previous pass.
 //!
-//! The `CleanUserAssertTy` pass runs at a distinct time from the
-//! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy`
+//! The `CleanAscribeUserType` pass runs at a distinct time from the
+//! `CleanEndRegions` pass. It is important that the `CleanAscribeUserType`
 //! pass runs after the MIR borrowck so that the NLL type checker can
-//! perform the type assertion when it encounters the `UserAssertTy`
+//! perform the type assertion when it encounters the `AscribeUserType`
 //! statements.
 
 use rustc_data_structures::fx::FxHashSet;
@@ -110,26 +110,26 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> {
     }
 }
 
-pub struct CleanUserAssertTy;
+pub struct CleanAscribeUserType;
 
-pub struct DeleteUserAssertTy;
+pub struct DeleteAscribeUserType;
 
-impl MirPass for CleanUserAssertTy {
+impl MirPass for CleanAscribeUserType {
     fn run_pass<'a, 'tcx>(&self,
                           _tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           _source: MirSource,
                           mir: &mut Mir<'tcx>) {
-        let mut delete = DeleteUserAssertTy;
+        let mut delete = DeleteAscribeUserType;
         delete.visit_mir(mir);
     }
 }
 
-impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy {
+impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType {
     fn visit_statement(&mut self,
                        block: BasicBlock,
                        statement: &mut Statement<'tcx>,
                        location: Location) {
-        if let StatementKind::UserAssertTy(..) = statement.kind {
+        if let StatementKind::AscribeUserType(..) = statement.kind {
             statement.make_nop();
         }
         self.super_statement(block, statement, location);
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 1ad713b4b7d..01edfd2bfc9 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -303,6 +303,7 @@ fn replace_result_variable<'tcx>(
     let new_ret = LocalDecl {
         mutability: Mutability::Mut,
         ty: ret_ty,
+        user_ty: None,
         name: None,
         source_info,
         visibility_scope: source_info.scope,
@@ -656,6 +657,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
     mir.local_decls[RETURN_PLACE] = LocalDecl {
         mutability: Mutability::Mut,
         ty: tcx.mk_unit(),
+        user_ty: None,
         name: None,
         source_info,
         visibility_scope: source_info.scope,
@@ -672,6 +674,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
             ty: gen_ty,
             mutbl: hir::Mutability::MutMutable,
         }),
+        user_ty: None,
         name: None,
         source_info,
         visibility_scope: source_info.scope,
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 1e05b07030e..19fb35be9d4 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -238,8 +238,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
         simplify_branches::SimplifyBranches::new("initial"),
         remove_noop_landing_pads::RemoveNoopLandingPads,
         simplify::SimplifyCfg::new("early-opt"),
-        // Remove all `UserAssertTy` statements.
-        cleanup_post_borrowck::CleanUserAssertTy,
+        // Remove all `AscribeUserType` statements.
+        cleanup_post_borrowck::CleanAscribeUserType,
 
         // These next passes must be executed together
         add_call_guards::CriticalCallEdges,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 81fc235c233..a2175dce33a 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1098,7 +1098,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 StatementKind::InlineAsm {..} |
                 StatementKind::EndRegion(_) |
                 StatementKind::Validate(..) |
-                StatementKind::UserAssertTy(..) |
+                StatementKind::AscribeUserType(..) |
                 StatementKind::Nop => {}
             }
         });
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index eacc23c9c4f..f7e44dde186 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -230,7 +230,7 @@ fn check_statement(
         | StatementKind::StorageDead(_)
         | StatementKind::Validate(..)
         | StatementKind::EndRegion(_)
-        | StatementKind::UserAssertTy(..)
+        | StatementKind::AscribeUserType(..)
         | StatementKind::Nop => Ok(()),
     }
 }
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index 04a7a81eb12..a2561d3d793 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -53,7 +53,7 @@ impl RemoveNoopLandingPads {
                 StatementKind::StorageLive(_) |
                 StatementKind::StorageDead(_) |
                 StatementKind::EndRegion(_) |
-                StatementKind::UserAssertTy(..) |
+                StatementKind::AscribeUserType(..) |
                 StatementKind::Nop => {
                     // These are all nops in a landing pad (there's some
                     // borrowck interaction between EndRegion and storage
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 9faaeea3f5b..f3e0f557363 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -163,7 +163,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             mir::StatementKind::InlineAsm { .. } |
             mir::StatementKind::EndRegion(_) |
             mir::StatementKind::Validate(..) |
-            mir::StatementKind::UserAssertTy(..) |
+            mir::StatementKind::AscribeUserType(..) |
             mir::StatementKind::Nop => continue,
             mir::StatementKind::SetDiscriminant{ .. } =>
                 span_bug!(stmt.source_info.span,
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 9f5b5040b09..710ccb2053b 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -17,6 +17,7 @@ use rustc::ty::item_path;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
 use std::fmt::Display;
+use std::fmt::Write as _;
 use std::fs;
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
@@ -493,14 +494,18 @@ fn write_scope_tree(
             };
 
             let indent = indent + INDENT.len();
-            let indented_var = format!(
-                "{0:1$}let {2}{3:?}: {4:?};",
+            let mut indented_var = format!(
+                "{0:1$}let {2}{3:?}: {4:?}",
                 INDENT,
                 indent,
                 mut_str,
                 local,
                 var.ty
             );
+            if let Some(user_ty) = var.user_ty {
+                write!(indented_var, " as {:?}", user_ty).unwrap();
+            }
+            indented_var.push_str(";");
             writeln!(
                 w,
                 "{0:1$} // \"{2}\" in {3}",
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index bca119660aa..2ee5415018f 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -22,6 +22,7 @@ use syntax::ast::*;
 use syntax::attr;
 use syntax::source_map::Spanned;
 use syntax::symbol::keywords;
+use syntax::ptr::P;
 use syntax::visit::{self, Visitor};
 use syntax_pos::Span;
 use errors;
@@ -98,14 +99,11 @@ impl<'a> AstValidator<'a> {
     }
 
     fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
-        match constness.node {
-            Constness::Const => {
-                struct_span_err!(self.session, constness.span, E0379,
-                                 "trait fns cannot be declared const")
-                    .span_label(constness.span, "trait fns cannot be const")
-                    .emit();
-            }
-            _ => {}
+        if constness.node == Constness::Const {
+            struct_span_err!(self.session, constness.span, E0379,
+                             "trait fns cannot be declared const")
+                .span_label(constness.span, "trait fns cannot be const")
+                .emit();
         }
     }
 
@@ -113,7 +111,7 @@ impl<'a> AstValidator<'a> {
         for bound in bounds {
             if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
                 let mut err = self.err_handler().struct_span_err(poly.span,
-                                    &format!("`?Trait` is not permitted in {}", where_));
+                    &format!("`?Trait` is not permitted in {}", where_));
                 if is_trait {
                     err.note(&format!("traits are `?{}` by default", poly.trait_ref.path));
                 }
@@ -152,26 +150,76 @@ impl<'a> AstValidator<'a> {
         // Check only lifetime parameters are present and that the lifetime
         // parameters that are present have no bounds.
         let non_lt_param_spans: Vec<_> = params.iter().filter_map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    if !param.bounds.is_empty() {
-                        let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
-                        self.err_handler()
-                            .span_err(spans, "lifetime bounds cannot be used in this context");
-                    }
-                    None
+            GenericParamKind::Lifetime { .. } => {
+                if !param.bounds.is_empty() {
+                    let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
+                    self.err_handler()
+                        .span_err(spans, "lifetime bounds cannot be used in this context");
                 }
-                _ => Some(param.ident.span),
-            }).collect();
+                None
+            }
+            _ => Some(param.ident.span),
+        }).collect();
         if !non_lt_param_spans.is_empty() {
             self.err_handler().span_err(non_lt_param_spans,
                 "only lifetime parameters can be used in this context");
         }
     }
+
+    /// With eRFC 2497, we need to check whether an expression is ambigious and warn or error
+    /// depending on the edition, this function handles that.
+    fn while_if_let_ambiguity(&self, expr: &P<Expr>) {
+        if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) {
+            let mut err = self.err_handler().struct_span_err(
+                span, &format!("ambigious use of `{}`", op_kind.to_string())
+            );
+
+            err.note(
+                "this will be a error until the `let_chains` feature is stabilized"
+            );
+            err.note(
+                "see rust-lang/rust#53668 for more information"
+            );
+
+            if let Ok(snippet) = self.session.source_map().span_to_snippet(span) {
+                err.span_suggestion(
+                    span, "consider adding parentheses", format!("({})", snippet),
+                );
+            }
+
+            err.emit();
+        }
+    }
+
+    /// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of
+    /// `&&` and `||` in a if-let statement be unambigious. This function returns a span and
+    /// a `BinOpKind` (either `&&` or `||` depending on what was ambigious) if it is determined
+    /// that the current expression parsed is ambigious and will break in future.
+    fn while_if_let_expr_ambiguity(&self, expr: &P<Expr>) -> Option<(Span, BinOpKind)> {
+        debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node);
+        match &expr.node {
+            ExprKind::Binary(op, _, _) if op.node == BinOpKind::And || op.node == BinOpKind::Or => {
+                Some((expr.span, op.node))
+            },
+            ExprKind::Range(ref lhs, ref rhs, _) => {
+                let lhs_ambigious = lhs.as_ref()
+                    .and_then(|lhs| self.while_if_let_expr_ambiguity(lhs));
+                let rhs_ambigious = rhs.as_ref()
+                    .and_then(|rhs| self.while_if_let_expr_ambiguity(rhs));
+
+                lhs_ambigious.or(rhs_ambigious)
+            }
+            _ => None,
+        }
+    }
+
 }
 
 impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_expr(&mut self, expr: &'a Expr) {
         match expr.node {
+            ExprKind::IfLet(_, ref expr, _, _) | ExprKind::WhileLet(_, ref expr, _, _) =>
+                self.while_if_let_ambiguity(&expr),
             ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
                 span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
             }
@@ -387,7 +435,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.err_handler().span_err(item.span,
                                                 "tuple and unit unions are not permitted");
                 }
-                if vdata.fields().len() == 0 {
+                if vdata.fields().is_empty() {
                     self.err_handler().span_err(item.span,
                                                 "unions cannot have zero fields");
                 }
@@ -414,14 +462,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_vis(&mut self, vis: &'a Visibility) {
-        match vis.node {
-            VisibilityKind::Restricted { ref path, .. } => {
-                path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
-                    self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
-                                                "generic arguments in visibility path");
-                });
-            }
-            _ => {}
+        if let VisibilityKind::Restricted { ref path, .. } = vis.node {
+            path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
+                self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
+                                            "generic arguments in visibility path");
+            });
         }
 
         visit::walk_vis(self, vis)
@@ -591,8 +636,7 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
             TyKind::ImplTrait(..) => {
                 if self.is_banned {
                     struct_span_err!(self.session, t.span, E0667,
-                                 "`impl Trait` is not allowed in path parameters")
-                        .emit();
+                        "`impl Trait` is not allowed in path parameters").emit();
                 }
             }
             TyKind::Path(ref qself, ref path) => {
@@ -616,7 +660,7 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
 
                 for (i, segment) in path.segments.iter().enumerate() {
                     // Allow `impl Trait` iff we're on the final path segment
-                    if i == (path.segments.len() - 1) {
+                    if i == path.segments.len() - 1 {
                         visit::walk_path_segment(self, path.span, segment);
                     } else {
                         self.with_ban(|this|
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index 3c5a0590c20..b65a2e3f0e5 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -61,10 +61,8 @@ pub fn print_ast_stats<'v>(krate: &'v ast::Crate, title: &str) {
 impl<'k> StatCollector<'k> {
 
     fn record<T>(&mut self, label: &'static str, id: Id, node: &T) {
-        if id != Id::None {
-            if !self.seen.insert(id) {
-                return
-            }
+        if id != Id::None && !self.seen.insert(id) {
+            return
         }
 
         let entry = self.data.entry(label).or_insert(NodeData {
@@ -135,40 +133,46 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_item(self, i)
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-
     fn visit_mod(&mut self, m: &'v hir::Mod, _s: Span, n: NodeId) {
         self.record("Mod", Id::None, m);
         hir_visit::walk_mod(self, m, n)
     }
+
     fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem) {
         self.record("ForeignItem", Id::Node(i.id), i);
         hir_visit::walk_foreign_item(self, i)
     }
+
     fn visit_local(&mut self, l: &'v hir::Local) {
         self.record("Local", Id::Node(l.id), l);
         hir_visit::walk_local(self, l)
     }
+
     fn visit_block(&mut self, b: &'v hir::Block) {
         self.record("Block", Id::Node(b.id), b);
         hir_visit::walk_block(self, b)
     }
+
     fn visit_stmt(&mut self, s: &'v hir::Stmt) {
         self.record("Stmt", Id::Node(s.node.id()), s);
         hir_visit::walk_stmt(self, s)
     }
+
     fn visit_arm(&mut self, a: &'v hir::Arm) {
         self.record("Arm", Id::None, a);
         hir_visit::walk_arm(self, a)
     }
+
     fn visit_pat(&mut self, p: &'v hir::Pat) {
         self.record("Pat", Id::Node(p.id), p);
         hir_visit::walk_pat(self, p)
     }
+
     fn visit_decl(&mut self, d: &'v hir::Decl) {
         self.record("Decl", Id::None, d);
         hir_visit::walk_decl(self, d)
     }
+
     fn visit_expr(&mut self, ex: &'v hir::Expr) {
         self.record("Expr", Id::Node(ex.id), ex);
         hir_visit::walk_expr(self, ex)
@@ -198,6 +202,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         self.record("TraitItem", Id::Node(ti.id), ti);
         hir_visit::walk_trait_item(self, ti)
     }
+
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
         self.record("ImplItem", Id::Node(ii.id), ii);
         hir_visit::walk_impl_item(self, ii)
@@ -220,31 +225,38 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         self.record("Variant", Id::None, v);
         hir_visit::walk_variant(self, v, g, item_id)
     }
+
     fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
         self.record("Lifetime", Id::Node(lifetime.id), lifetime);
         hir_visit::walk_lifetime(self, lifetime)
     }
+
     fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: hir::HirId, span: Span) {
         self.record("QPath", Id::None, qpath);
         hir_visit::walk_qpath(self, qpath, id, span)
     }
+
     fn visit_path(&mut self, path: &'v hir::Path, _id: hir::HirId) {
         self.record("Path", Id::None, path);
         hir_visit::walk_path(self, path)
     }
+
     fn visit_path_segment(&mut self,
                           path_span: Span,
                           path_segment: &'v hir::PathSegment) {
         self.record("PathSegment", Id::None, path_segment);
         hir_visit::walk_path_segment(self, path_span, path_segment)
     }
+
     fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding) {
         self.record("TypeBinding", Id::Node(type_binding.id), type_binding);
         hir_visit::walk_assoc_type_binding(self, type_binding)
     }
+
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
         self.record("Attribute", Id::Attr(attr.id), attr);
     }
+
     fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef) {
         self.record("MacroDef", Id::Node(macro_def.id), macro_def);
         hir_visit::walk_macro_def(self, macro_def)
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 44030c284fd..61c2ac161bb 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -114,9 +114,8 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 };
 
                 if loop_id != ast::DUMMY_NODE_ID {
-                    match self.hir_map.find(loop_id).unwrap() {
-                        Node::Block(_) => return,
-                        _=> (),
+                    if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() {
+                        return
                     }
                 }
 
@@ -153,10 +152,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
 
                 self.require_break_cx("break", e.span);
             }
-            hir::ExprKind::Continue(label) => {
-                self.require_label_in_labeled_block(e.span, &label, "continue");
+            hir::ExprKind::Continue(destination) => {
+                self.require_label_in_labeled_block(e.span, &destination, "continue");
 
-                match label.target_id {
+                match destination.target_id {
                     Ok(loop_id) => {
                         if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
                             struct_span_err!(self.sess, e.span, E0696,
@@ -171,7 +170,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
                         self.emit_unlabled_cf_in_while_condition(e.span, "continue");
                     }
-                    _ => {}
+                    Err(_) => {}
                 }
                 self.require_break_cx("continue", e.span)
             },
@@ -192,8 +191,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
 
     fn require_break_cx(&self, name: &str, span: Span) {
         match self.cx {
-            LabeledBlock |
-            Loop(_) => {}
+            LabeledBlock | Loop(_) => {}
             Closure => {
                 struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
                 .span_label(span, "cannot break inside of a closure")
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 3206fa6e172..0120b5bc532 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -65,15 +65,12 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_mir(mir);
     }
 
-    fn visit_basic_block_data(&mut self,
-                              block: BasicBlock,
-                              data: &BasicBlockData<'tcx>) {
+    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
         self.record("BasicBlockData", data);
         self.super_basic_block_data(block, data);
     }
 
-    fn visit_source_scope_data(&mut self,
-                                   scope_data: &SourceScopeData) {
+    fn visit_source_scope_data(&mut self, scope_data: &SourceScopeData) {
         self.record("SourceScopeData", scope_data);
         self.super_source_scope_data(scope_data);
     }
@@ -92,7 +89,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
             StatementKind::StorageLive(..) => "StatementKind::StorageLive",
             StatementKind::StorageDead(..) => "StatementKind::StorageDead",
             StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
-            StatementKind::UserAssertTy(..) => "StatementKind::UserAssertTy",
+            StatementKind::AscribeUserType(..) => "StatementKind::AscribeUserType",
             StatementKind::Nop => "StatementKind::Nop",
         }, &statement.kind);
         self.super_statement(block, statement, location);
@@ -130,9 +127,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_terminator_kind(block, kind, location);
     }
 
-    fn visit_assert_message(&mut self,
-                            msg: &AssertMessage<'tcx>,
-                            location: Location) {
+    fn visit_assert_message(&mut self, msg: &AssertMessage<'tcx>, location: Location) {
         self.record("AssertMessage", msg);
         self.record(match *msg {
             EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
@@ -151,9 +146,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_assert_message(msg, location);
     }
 
-    fn visit_rvalue(&mut self,
-                    rvalue: &Rvalue<'tcx>,
-                    location: Location) {
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         self.record("Rvalue", rvalue);
         let rvalue_kind = match *rvalue {
             Rvalue::Use(..) => "Rvalue::Use",
@@ -184,9 +177,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_rvalue(rvalue, location);
     }
 
-    fn visit_operand(&mut self,
-                     operand: &Operand<'tcx>,
-                     location: Location) {
+    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         self.record("Operand", operand);
         self.record(match *operand {
             Operand::Copy(..) => "Operand::Copy",
@@ -234,42 +225,32 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_projection_elem(place, context, location);
     }
 
-    fn visit_constant(&mut self,
-                      constant: &Constant<'tcx>,
-                      location: Location) {
+    fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
         self.record("Constant", constant);
         self.super_constant(constant, location);
     }
 
-    fn visit_source_info(&mut self,
-                         source_info: &SourceInfo) {
+    fn visit_source_info(&mut self, source_info: &SourceInfo) {
         self.record("SourceInfo", source_info);
         self.super_source_info(source_info);
     }
 
-    fn visit_closure_substs(&mut self,
-                            substs: &ClosureSubsts<'tcx>,
-                            _: Location) {
+    fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, _: Location) {
         self.record("ClosureSubsts", substs);
         self.super_closure_substs(substs);
     }
 
-    fn visit_const(&mut self,
-                   constant: &&'tcx ty::Const<'tcx>,
-                   _: Location) {
+    fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
         self.record("Const", constant);
         self.super_const(constant);
     }
 
-    fn visit_local_decl(&mut self,
-                        local: Local,
-                        local_decl: &LocalDecl<'tcx>) {
+    fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
         self.record("LocalDecl", local_decl);
         self.super_local_decl(local, local_decl);
     }
 
-    fn visit_source_scope(&mut self,
-                              scope: &SourceScope) {
+    fn visit_source_scope(&mut self, scope: &SourceScope) {
         self.record("VisiblityScope", scope);
         self.super_source_scope(scope);
     }
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index ea4fba3e124..74b010f57b0 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -41,8 +41,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax_pos::{Span, DUMMY_SP};
 use self::Promotability::*;
-use std::ops::{BitAnd, BitOr};
-
+use std::ops::{BitAnd, BitAndAssign, BitOr};
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
@@ -114,7 +113,7 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
 }
 
 #[must_use]
-#[derive(Debug, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 enum Promotability {
     Promotable,
     NotPromotable
@@ -125,23 +124,25 @@ impl BitAnd for Promotability {
 
     fn bitand(self, rhs: Self) -> Self {
         match (self, rhs) {
-            (Promotable, NotPromotable) => NotPromotable,
-            (NotPromotable, Promotable) => NotPromotable,
-            (NotPromotable, NotPromotable) => NotPromotable,
             (Promotable, Promotable) => Promotable,
+            _ => NotPromotable,
         }
     }
 }
 
+impl BitAndAssign for Promotability {
+    fn bitand_assign(&mut self, rhs: Self) {
+        *self = *self & rhs
+    }
+}
+
 impl BitOr for Promotability {
     type Output = Self;
 
     fn bitor(self, rhs: Self) -> Self {
         match (self, rhs) {
-            (Promotable, NotPromotable) => Promotable,
-            (NotPromotable, Promotable) => Promotable,
             (NotPromotable, NotPromotable) => NotPromotable,
-            (Promotable, Promotable) => Promotable,
+            _ => Promotable,
         }
     }
 }
@@ -161,7 +162,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
 
     fn handle_const_fn_call(&mut self, def_id: DefId,
                             ret_ty: Ty<'gcx>, span: Span) -> Promotability {
-        if let NotPromotable = self.type_promotability(ret_ty) {
+        if self.type_promotability(ret_ty) == NotPromotable {
             return NotPromotable;
         }
 
@@ -266,9 +267,8 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
                             }
                         }
 
-                        match local.init {
-                            Some(ref expr) => { let _ = self.check_expr(&expr); },
-                            None => {},
+                        if let Some(ref expr) = local.init {
+                            let _ = self.check_expr(&expr);
                         }
                         NotPromotable
                     }
@@ -287,7 +287,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
     fn check_expr(&mut self, ex: &'tcx hir::Expr) -> Promotability {
         let node_ty = self.tables.node_id_to_type(ex.hir_id);
         let mut outer = check_expr_kind(self, ex, node_ty);
-        outer = outer & check_adjustments(self, ex);
+        outer &= check_adjustments(self, ex);
 
         // Handle borrows on (or inside the autorefs of) this expression.
         if self.mut_rvalue_borrows.remove(&ex.id) {
@@ -303,7 +303,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
     fn check_block(&mut self, block: &'tcx hir::Block) -> Promotability {
         let mut iter_result = Promotable;
         for index in block.stmts.iter() {
-            iter_result = iter_result & self.check_stmt(index);
+            iter_result &= self.check_stmt(index);
         }
         match block.expr {
             Some(ref box_expr) => iter_result & self.check_expr(&*box_expr),
@@ -336,10 +336,7 @@ fn check_expr_kind<'a, 'tcx>(
         }
         hir::ExprKind::Unary(op, ref expr) => {
             let expr_promotability = v.check_expr(expr);
-            if v.tables.is_method_call(e) {
-                return NotPromotable;
-            }
-            if op == hir::UnDeref {
+            if v.tables.is_method_call(e) || op == hir::UnDeref {
                 return NotPromotable;
             }
             expr_promotability
@@ -353,8 +350,8 @@ fn check_expr_kind<'a, 'tcx>(
             match v.tables.node_id_to_type(lhs.hir_id).sty {
                 ty::RawPtr(_) => {
                     assert!(op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne ||
-                        op.node == hir::BinOpKind::Le || op.node == hir::BinOpKind::Lt ||
-                        op.node == hir::BinOpKind::Ge || op.node == hir::BinOpKind::Gt);
+                            op.node == hir::BinOpKind::Le || op.node == hir::BinOpKind::Lt ||
+                            op.node == hir::BinOpKind::Ge || op.node == hir::BinOpKind::Gt);
 
                     NotPromotable
                 }
@@ -400,7 +397,6 @@ fn check_expr_kind<'a, 'tcx>(
                         debug!("Reference to Static(id={:?}) is unpromotable as it is not \
                                referenced from a static", did);
                         NotPromotable
-
                     }
                 }
 
@@ -425,7 +421,7 @@ fn check_expr_kind<'a, 'tcx>(
         hir::ExprKind::Call(ref callee, ref hirvec) => {
             let mut call_result = v.check_expr(callee);
             for index in hirvec.iter() {
-                call_result = call_result & v.check_expr(index);
+                call_result &= v.check_expr(index);
             }
             let mut callee = &**callee;
             loop {
@@ -464,7 +460,7 @@ fn check_expr_kind<'a, 'tcx>(
         hir::ExprKind::MethodCall(ref _pathsegment, ref _span, ref hirvec) => {
             let mut method_call_result = Promotable;
             for index in hirvec.iter() {
-                method_call_result = method_call_result & v.check_expr(index);
+                method_call_result &= v.check_expr(index);
             }
             if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
                 let def_id = def.def_id();
@@ -483,11 +479,10 @@ fn check_expr_kind<'a, 'tcx>(
         hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => {
             let mut struct_result = Promotable;
             for index in hirvec.iter() {
-                struct_result = struct_result & v.check_expr(&index.expr);
+                struct_result &= v.check_expr(&index.expr);
             }
-            match *option_expr {
-                Some(ref expr) => { struct_result = struct_result & v.check_expr(&expr); },
-                None => {},
+            if let Some(ref expr) = *option_expr {
+                struct_result &= v.check_expr(&expr);
             }
             if let ty::Adt(adt, ..) = v.tables.expr_ty(e).sty {
                 // unsafe_cell_type doesn't necessarily exist with no_core
@@ -506,7 +501,7 @@ fn check_expr_kind<'a, 'tcx>(
         }
 
         hir::ExprKind::Closure(_capture_clause, ref _box_fn_decl,
-                         body_id, _span, _option_generator_movability) => {
+                               body_id, _span, _option_generator_movability) => {
             let nested_body_promotable = v.check_nested_body(body_id);
             // Paths in constant contexts cannot refer to local variables,
             // as there are none, and thus closures can't have upvars there.
@@ -543,7 +538,7 @@ fn check_expr_kind<'a, 'tcx>(
         hir::ExprKind::Array(ref hirvec) => {
             let mut array_result = Promotable;
             for index in hirvec.iter() {
-                array_result = array_result & v.check_expr(index);
+                array_result &= v.check_expr(index);
             }
             array_result
         }
@@ -555,7 +550,7 @@ fn check_expr_kind<'a, 'tcx>(
         hir::ExprKind::Tup(ref hirvec) => {
             let mut tup_result = Promotable;
             for index in hirvec.iter() {
-                tup_result = tup_result & v.check_expr(index);
+                tup_result &= v.check_expr(index);
             }
             tup_result
         }
@@ -576,12 +571,9 @@ fn check_expr_kind<'a, 'tcx>(
             let _ = v.check_expr(expr);
             for index in hirvec_arm.iter() {
                 let _ = v.check_expr(&*index.body);
-                match index.guard {
-                    Some(hir::Guard::If(ref expr)) => {
-                        let _ = v.check_expr(&expr);
-                    },
-                    None => {},
-                };
+                if let Some(hir::Guard::If(ref expr)) = index.guard {
+                    let _ = v.check_expr(&expr);
+                }
             }
             NotPromotable
         }
@@ -589,10 +581,9 @@ fn check_expr_kind<'a, 'tcx>(
         hir::ExprKind::If(ref lhs, ref rhs, ref option_expr) => {
             let _ = v.check_expr(lhs);
             let _ = v.check_expr(rhs);
-            match option_expr {
-                Some(ref expr) => { let _ = v.check_expr(&expr); },
-                None => {},
-            };
+            if let Some(ref expr) = option_expr {
+                let _ = v.check_expr(&expr);
+            }
             NotPromotable
         }
 
@@ -610,9 +601,8 @@ fn check_expr_kind<'a, 'tcx>(
 
         // More control flow (also not very meaningful).
         hir::ExprKind::Break(_, ref option_expr) | hir::ExprKind::Ret(ref option_expr) => {
-            match *option_expr {
-                Some(ref expr) => { let _ = v.check_expr(&expr); },
-                None => {},
+            if let Some(ref expr) = *option_expr {
+                 let _ = v.check_expr(&expr);
             }
             NotPromotable
         }
@@ -635,10 +625,7 @@ fn check_expr_kind<'a, 'tcx>(
         }
 
         hir::ExprKind::InlineAsm(ref _inline_asm, ref hirvec_lhs, ref hirvec_rhs) => {
-            for index in hirvec_lhs.iter() {
-                let _ = v.check_expr(index);
-            }
-            for index in hirvec_rhs.iter() {
+            for index in hirvec_lhs.iter().chain(hirvec_rhs.iter()) {
                 let _ = v.check_expr(index);
             }
             NotPromotable
@@ -703,11 +690,8 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
         // These occur when we convert a &T or *T to a *U, as well as
         // when making a thin pointer (e.g., `*T`) into a fat pointer
         // (e.g., `*Trait`).
-        match loan_cause {
-            euv::LoanCause::AutoUnsafe => {
-                return;
-            }
-            _ => {}
+        if let euv::LoanCause::AutoUnsafe = loan_cause {
+            return;
         }
 
         let mut cur = cmt;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 63f643d7a29..d1a05964c8f 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -39,6 +39,7 @@ use syntax::ext::base::{MacroKind, SyntaxExtension};
 use syntax::ext::base::Determinacy::Undetermined;
 use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
+use syntax::feature_gate::is_builtin_attr;
 use syntax::parse::token::{self, Token};
 use syntax::std_inject::injected_crate_name;
 use syntax::symbol::keywords;
@@ -194,27 +195,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         // ergonomically unacceptable.
         let emit_uniform_paths_canary =
             !uniform_paths_canary_emitted &&
-            uniform_paths &&
+            self.session.rust_2018() &&
             starts_with_non_keyword;
         if emit_uniform_paths_canary {
             let source = prefix_start.unwrap();
 
-            // HACK(eddyb) For `use x::{self, ...};`, use the ID of the
-            // `self` nested import for the canary. This allows the
-            // ambiguity reporting scope to ignore false positives
-            // in the same way it does for `use x;` (by comparing IDs).
-            let mut canary_id = id;
-            if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
-                for &(ref use_tree, id) in items {
-                    if let ast::UseTreeKind::Simple(..) = use_tree.kind {
-                        if use_tree.ident().name == keywords::SelfValue.name() {
-                            canary_id = id;
-                            break;
-                        }
-                    }
-                }
-            }
-
             // Helper closure to emit a canary with the given base path.
             let emit = |this: &mut Self, base: Option<Ident>| {
                 let subclass = SingleImport {
@@ -234,7 +219,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     base.into_iter().collect(),
                     subclass.clone(),
                     source.span,
-                    canary_id,
+                    id,
                     root_use_tree.span,
                     root_id,
                     ty::Visibility::Invisible,
@@ -833,7 +818,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                            binding: &'a NameBinding<'a>,
                            span: Span,
                            allow_shadowing: bool) {
-        if self.macro_prelude.insert(name, binding).is_some() && !allow_shadowing {
+        if self.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
             let msg = format!("`{}` is already in scope", name);
             let note =
                 "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
@@ -1073,4 +1058,13 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
             }
         }
     }
+
+    fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
+        if !attr.is_sugared_doc && is_builtin_attr(attr) {
+            self.resolver.current_module.builtin_attrs.borrow_mut().push((
+                attr.path.segments[0].ident, self.expansion, self.current_legacy_scope
+            ));
+        }
+        visit::walk_attribute(self, attr);
+    }
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 5cb615554ee..8c769094f52 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -81,7 +81,7 @@ use std::mem::replace;
 use rustc_data_structures::sync::Lrc;
 
 use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
-use macros::{InvocationData, LegacyBinding};
+use macros::{InvocationData, LegacyBinding, LegacyScope};
 
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
@@ -160,8 +160,6 @@ enum ResolutionError<'a> {
     SelfImportCanOnlyAppearOnceInTheList,
     /// error E0431: `self` import can only appear in an import list with a non-empty prefix
     SelfImportOnlyInImportListWithNonEmptyPrefix,
-    /// error E0432: unresolved import
-    UnresolvedImport(Option<(Span, &'a str, &'a str)>),
     /// error E0433: failed to resolve
     FailedToResolve(&'a str),
     /// error E0434: can't capture dynamic environment in a fn item
@@ -370,17 +368,6 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             err.span_label(span, "can only appear in an import list with a non-empty prefix");
             err
         }
-        ResolutionError::UnresolvedImport(name) => {
-            let (span, msg) = match name {
-                Some((sp, n, _)) => (sp, format!("unresolved import `{}`", n)),
-                None => (span, "unresolved import".to_owned()),
-            };
-            let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg);
-            if let Some((_, _, p)) = name {
-                err.span_label(span, p);
-            }
-            err
-        }
         ResolutionError::FailedToResolve(msg) => {
             let mut err = struct_span_err!(resolver.session, span, E0433,
                                            "failed to resolve. {}", msg);
@@ -1023,8 +1010,9 @@ pub struct ModuleData<'a> {
     normal_ancestor_id: DefId,
 
     resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
-    legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, MacroKind, Option<Def>)>>,
+    legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>,
     macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
+    builtin_attrs: RefCell<Vec<(Ident, Mark, LegacyScope<'a>)>>,
 
     // Macro invocations that can expand into items in this module.
     unresolved_invocations: RefCell<FxHashSet<Mark>>,
@@ -1063,6 +1051,7 @@ impl<'a> ModuleData<'a> {
             resolutions: RefCell::new(FxHashMap()),
             legacy_macro_resolutions: RefCell::new(Vec::new()),
             macro_resolutions: RefCell::new(Vec::new()),
+            builtin_attrs: RefCell::new(Vec::new()),
             unresolved_invocations: RefCell::new(FxHashSet()),
             no_implicit_prelude: false,
             glob_importers: RefCell::new(Vec::new()),
@@ -1278,23 +1267,30 @@ impl<'a> NameBinding<'a> {
         }
     }
 
+    fn macro_kind(&self) -> Option<MacroKind> {
+        match self.def_ignoring_ambiguity() {
+            Def::Macro(_, kind) => Some(kind),
+            Def::NonMacroAttr(..) => Some(MacroKind::Attr),
+            _ => None,
+        }
+    }
+
     fn descr(&self) -> &'static str {
         if self.is_extern_crate() { "extern crate" } else { self.def().kind_name() }
     }
 
-    // Suppose that we resolved macro invocation with `invoc_id` to binding `binding` at some
-    // expansion round `max(invoc_id, binding)` when they both emerged from macros.
+    // Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding`
+    // at some expansion round `max(invoc, binding)` when they both emerged from macros.
     // Then this function returns `true` if `self` may emerge from a macro *after* that
     // in some later round and screw up our previously found resolution.
     // See more detailed explanation in
     // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049
-    fn may_appear_after(&self, invoc_id: Mark, binding: &NameBinding) -> bool {
-        // self > max(invoc_id, binding) => !(self <= invoc_id || self <= binding)
+    fn may_appear_after(&self, invoc_parent_expansion: Mark, binding: &NameBinding) -> bool {
+        // self > max(invoc, binding) => !(self <= invoc || self <= binding)
         // Expansions are partially ordered, so "may appear after" is an inversion of
         // "certainly appears before or simultaneously" and includes unordered cases.
         let self_parent_expansion = self.expansion;
         let other_parent_expansion = binding.expansion;
-        let invoc_parent_expansion = invoc_id.parent();
         let certainly_before_other_or_simultaneously =
             other_parent_expansion.is_descendant_of(self_parent_expansion);
         let certainly_before_invoc_or_simultaneously =
@@ -1440,8 +1436,8 @@ pub struct Resolver<'a, 'b: 'a> {
 
     crate_loader: &'a mut CrateLoader<'b>,
     macro_names: FxHashSet<Ident>,
-    macro_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
-    unshadowable_attrs: FxHashMap<Name, &'a NameBinding<'a>>,
+    builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
+    macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
     pub all_macros: FxHashMap<Name, Def>,
     macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
     macro_defs: FxHashMap<Mark, DefId>,
@@ -1757,8 +1753,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
 
             crate_loader,
             macro_names: FxHashSet(),
-            macro_prelude: FxHashMap(),
-            unshadowable_attrs: FxHashMap(),
+            builtin_macros: FxHashMap(),
+            macro_use_prelude: FxHashMap(),
             all_macros: FxHashMap(),
             macro_map: FxHashMap(),
             invocations,
@@ -3340,10 +3336,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                 };
             }
         }
-        let is_global = self.macro_prelude.get(&path[0].name).cloned()
-            .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
-        if primary_ns != MacroNS && (is_global ||
-                                     self.macro_names.contains(&path[0].modern())) {
+        if primary_ns != MacroNS &&
+           (self.macro_names.contains(&path[0].modern()) ||
+            self.builtin_macros.get(&path[0].name).cloned()
+                               .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang) ||
+            self.macro_use_prelude.get(&path[0].name).cloned()
+                                  .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) {
             // Return some dummy definition, it's enough for error reporting.
             return Some(
                 PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
@@ -3497,16 +3495,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         path_span: Span,
         crate_lint: CrateLint,
     ) -> PathResult<'a> {
-        self.resolve_path_with_invoc_id(base_module, path, opt_ns, Mark::root(),
-                                        record_used, path_span, crate_lint)
+        self.resolve_path_with_parent_expansion(base_module, path, opt_ns, Mark::root(),
+                                                record_used, path_span, crate_lint)
     }
 
-    fn resolve_path_with_invoc_id(
+    fn resolve_path_with_parent_expansion(
         &mut self,
         base_module: Option<ModuleOrUniformRoot<'a>>,
         path: &[Ident],
         opt_ns: Option<Namespace>, // `None` indicates a module path
-        invoc_id: Mark,
+        parent_expansion: Mark,
         record_used: bool,
         path_span: Span,
         crate_lint: CrateLint,
@@ -3599,8 +3597,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                 self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
             } else if opt_ns == Some(MacroNS) {
                 assert!(ns == TypeNS);
-                self.resolve_lexical_macro_path_segment(ident, ns, invoc_id, record_used,
-                                                        record_used, false, path_span)
+                self.resolve_lexical_macro_path_segment(ident, ns, None, parent_expansion,
+                                                        record_used, record_used, path_span)
                                                         .map(|(binding, _)| binding)
             } else {
                 let record_used_id =
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 93874ee0e85..7733ce475e3 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -109,6 +109,13 @@ pub struct ProcMacError {
     warn_msg: &'static str,
 }
 
+// For compatibility bang macros are skipped when resolving potentially built-in attributes.
+fn macro_kind_mismatch(name: Name, requirement: Option<MacroKind>, candidate: Option<MacroKind>)
+                       -> bool {
+    requirement == Some(MacroKind::Attr) && candidate == Some(MacroKind::Bang) &&
+    (name == "test" || name == "bench" || is_builtin_attr_name(name))
+}
+
 impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
     fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
@@ -214,24 +221,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
             vis: ty::Visibility::Invisible,
             expansion: Mark::root(),
         });
-        self.macro_prelude.insert(ident.name, binding);
-    }
-
-    fn add_unshadowable_attr(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
-        let def_id = DefId {
-            krate: BUILTIN_MACROS_CRATE,
-            index: DefIndex::from_array_index(self.macro_map.len(),
-                                              DefIndexAddressSpace::Low),
-        };
-        let kind = ext.kind();
-        self.macro_map.insert(def_id, ext);
-        let binding = self.arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Def(Def::Macro(def_id, kind), false),
-            span: DUMMY_SP,
-            vis: ty::Visibility::Invisible,
-            expansion: Mark::root(),
-        });
-        self.unshadowable_attrs.insert(ident.name, binding);
+        if self.builtin_macros.insert(ident.name, binding).is_some() {
+            self.session.span_err(ident.span,
+                                  &format!("built-in macro `{}` was already defined", ident));
+        }
     }
 
     fn resolve_imports(&mut self) {
@@ -249,7 +242,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
                 attr::mark_known(&attrs[i]);
             }
 
-            match self.macro_prelude.get(&name).cloned() {
+            match self.builtin_macros.get(&name).cloned() {
                 Some(binding) => match *binding.get_macro(self) {
                     MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                         return Some(attrs.remove(i))
@@ -285,7 +278,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
                     }
                     let trait_name = traits[j].segments[0].ident.name;
                     let legacy_name = Symbol::intern(&format!("derive_{}", trait_name));
-                    if !self.macro_prelude.contains_key(&legacy_name) {
+                    if !self.builtin_macros.contains_key(&legacy_name) {
                         continue
                     }
                     let span = traits.remove(j).span;
@@ -327,7 +320,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
         None
     }
 
-    fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
+    fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
                                 -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
         let (path, kind, derives_in_scope) = match invoc.kind {
             InvocationKind::Attr { attr: None, .. } =>
@@ -340,7 +333,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
                 (path, MacroKind::Derive, &[][..]),
         };
 
-        let (def, ext) = self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?;
+        let (def, ext) = self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?;
 
         if let Def::Macro(def_id, _) = def {
             self.macro_defs.insert(invoc.expansion_data.mark, def_id);
@@ -355,10 +348,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
         Ok(Some(ext))
     }
 
-    fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+    fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
                           derives_in_scope: &[ast::Path], force: bool)
                           -> Result<Lrc<SyntaxExtension>, Determinacy> {
-        Ok(self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?.1)
+        Ok(self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?.1)
     }
 
     fn check_unused_macros(&self) {
@@ -380,10 +373,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
 }
 
 impl<'a, 'cl> Resolver<'a, 'cl> {
-    fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+    fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
                             derives_in_scope: &[ast::Path], force: bool)
                             -> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
-        let def = self.resolve_macro_to_def_inner(path, kind, scope, derives_in_scope, force);
+        let def = self.resolve_macro_to_def_inner(path, kind, invoc_id, derives_in_scope, force);
 
         // Report errors and enforce feature gates for the resolved macro.
         if def != Err(Determinacy::Undetermined) {
@@ -453,8 +446,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         let ast::Path { ref segments, span } = *path;
         let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
         let invocation = self.invocations[&invoc_id];
-        let module = invocation.module.get();
-        self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };
+        let parent_expansion = invoc_id.parent();
+        let parent_legacy_scope = invocation.parent_legacy_scope.get();
+        self.current_module = invocation.module.get().nearest_item_scope();
 
         // Possibly apply the macro helper hack
         if kind == MacroKind::Bang && path.len() == 1 &&
@@ -464,8 +458,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         }
 
         if path.len() > 1 {
-            let def = match self.resolve_path_with_invoc_id(None, &path, Some(MacroNS), invoc_id,
-                                                            false, span, CrateLint::No) {
+            let def = match self.resolve_path_with_parent_expansion(None, &path, Some(MacroNS),
+                                                                    parent_expansion, false, span,
+                                                                    CrateLint::No) {
                 PathResult::NonModule(path_res) => match path_res.base_def() {
                     Def::Err => Err(Determinacy::Determined),
                     def @ _ => {
@@ -485,25 +480,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     Err(Determinacy::Determined)
                 },
             };
-            self.current_module.nearest_item_scope().macro_resolutions.borrow_mut()
+            self.current_module.macro_resolutions.borrow_mut()
                 .push((path.into_boxed_slice(), span));
             return def;
         }
 
-        if kind == MacroKind::Attr {
-            if let Some(ext) = self.unshadowable_attrs.get(&path[0].name) {
-                return Ok(ext.def());
-            }
-        }
-
         let legacy_resolution = self.resolve_legacy_scope(
-            path[0], invoc_id, invocation.parent_legacy_scope.get(), false
+            path[0], Some(kind), parent_expansion, parent_legacy_scope, false
         );
         let result = if let Some(legacy_binding) = legacy_resolution {
             Ok(legacy_binding.def())
         } else {
-            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, invoc_id, false, force,
-                                                          kind == MacroKind::Attr, span) {
+            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, Some(kind),
+                                                          parent_expansion, false, force, span) {
                 Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
                 Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
                 Err(Determinacy::Determined) => {
@@ -513,8 +502,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             }
         };
 
-        self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
-            .push((invoc_id, path[0], kind, result.ok()));
+        self.current_module.legacy_macro_resolutions.borrow_mut()
+            .push((path[0], kind, parent_expansion, parent_legacy_scope, result.ok()));
 
         if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
             return result;
@@ -561,10 +550,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         &mut self,
         mut ident: Ident,
         ns: Namespace,
-        invoc_id: Mark,
+        kind: Option<MacroKind>,
+        parent_expansion: Mark,
         record_used: bool,
         force: bool,
-        is_attr: bool,
         path_span: Span,
     ) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
         // General principles:
@@ -585,14 +574,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         // (Macro NS)
         // 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
         //    (open, not controlled).
-        // 2. Macro prelude (language, standard library, user-defined legacy plugins lumped into
-        //    one set) (open, the open part is from macro expansions, not controlled).
+        // 2. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
         // 2a. User-defined prelude from macro-use
         //    (open, the open part is from macro expansions, not controlled).
-        // 2b. Standard library prelude, currently just a macro-use (closed, controlled)
-        // 2c. Language prelude, perhaps including builtin attributes
-        //    (closed, controlled, except for legacy plugins).
-        // 3. Builtin attributes (closed, controlled).
+        // 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
+        // 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
+        // 4. Language prelude: builtin attributes (closed, controlled).
 
         assert!(ns == TypeNS  || ns == MacroNS);
         assert!(force || !record_used); // `record_used` implies `force`
@@ -613,12 +600,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
 
         enum WhereToResolve<'a> {
             Module(Module<'a>),
-            MacroPrelude,
+            MacroUsePrelude,
+            BuiltinMacros,
             BuiltinAttrs,
             ExternPrelude,
             ToolPrelude,
             StdLibPrelude,
-            PrimitiveTypes,
+            BuiltinTypes,
         }
 
         // Go through all the scopes and try to resolve the name.
@@ -639,8 +627,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     self.current_module = orig_current_module;
                     binding.map(|binding| (binding, FromPrelude(false)))
                 }
-                WhereToResolve::MacroPrelude => {
-                    match self.macro_prelude.get(&ident.name).cloned() {
+                WhereToResolve::MacroUsePrelude => {
+                    match self.macro_use_prelude.get(&ident.name).cloned() {
+                        Some(binding) => Ok((binding, FromPrelude(true))),
+                        None => Err(Determinacy::Determined),
+                    }
+                }
+                WhereToResolve::BuiltinMacros => {
+                    match self.builtin_macros.get(&ident.name).cloned() {
                         Some(binding) => Ok((binding, FromPrelude(true))),
                         None => Err(Determinacy::Determined),
                     }
@@ -649,7 +643,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     // FIXME: Only built-in attributes are not considered as candidates for
                     // non-attributes to fight off regressions on stable channel (#53205).
                     // We need to come up with some more principled approach instead.
-                    if is_attr && is_builtin_attr_name(ident.name) {
+                    if kind == Some(MacroKind::Attr) && is_builtin_attr_name(ident.name) {
                         let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
                                        ty::Visibility::Public, ident.span, Mark::root())
                                        .to_name_binding(self.arenas);
@@ -708,7 +702,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     }
                     result
                 }
-                WhereToResolve::PrimitiveTypes => {
+                WhereToResolve::BuiltinTypes => {
                     if let Some(prim_ty) =
                             self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
                         let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
@@ -728,19 +722,20 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                             None => {
                                 use_prelude = !module.no_implicit_prelude;
                                 if ns == MacroNS {
-                                    WhereToResolve::MacroPrelude
+                                    WhereToResolve::MacroUsePrelude
                                 } else {
                                     WhereToResolve::ExternPrelude
                                 }
                             }
                         }
                     }
-                    WhereToResolve::MacroPrelude => WhereToResolve::BuiltinAttrs,
+                    WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
+                    WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
                     WhereToResolve::BuiltinAttrs => break, // nowhere else to search
                     WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
                     WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
-                    WhereToResolve::StdLibPrelude => WhereToResolve::PrimitiveTypes,
-                    WhereToResolve::PrimitiveTypes => break, // nowhere else to search
+                    WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
+                    WhereToResolve::BuiltinTypes => break, // nowhere else to search
                 };
 
                 continue;
@@ -748,6 +743,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
 
             match result {
                 Ok(result) => {
+                    if macro_kind_mismatch(ident.name, kind, result.0.macro_kind()) {
+                        continue_search!();
+                    }
+
                     if !record_used {
                         return Ok(result);
                     }
@@ -756,7 +755,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         // Found another solution, if the first one was "weak", report an error.
                         if result.0.def() != innermost_result.0.def() &&
                            (innermost_result.0.is_glob_import() ||
-                            innermost_result.0.may_appear_after(invoc_id, result.0)) {
+                            innermost_result.0.may_appear_after(parent_expansion, result.0)) {
                             self.ambiguity_errors.push(AmbiguityError {
                                 ident,
                                 b1: innermost_result.0,
@@ -784,9 +783,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         }
 
         let determinacy = Determinacy::determined(force);
-        if determinacy == Determinacy::Determined && is_attr {
+        if determinacy == Determinacy::Determined && kind == Some(MacroKind::Attr) {
             // For single-segment attributes interpret determinate "no resolution" as a custom
-            // attribute. (Lexical resolution implies the first segment and is_attr should imply
+            // attribute. (Lexical resolution implies the first segment and attr kind should imply
             // the last segment, so we are certainly working with a single-segment attribute here.)
             assert!(ns == MacroNS);
             let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom),
@@ -800,10 +799,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
 
     fn resolve_legacy_scope(&mut self,
                             ident: Ident,
-                            invoc_id: Mark,
-                            invoc_parent_legacy_scope: LegacyScope<'a>,
+                            kind: Option<MacroKind>,
+                            parent_expansion: Mark,
+                            parent_legacy_scope: LegacyScope<'a>,
                             record_used: bool)
                             -> Option<&'a NameBinding<'a>> {
+        if macro_kind_mismatch(ident.name, kind, Some(MacroKind::Bang)) {
+            return None;
+        }
+
         let ident = ident.modern();
 
         // This is *the* result, resolution from the scope closest to the resolved identifier.
@@ -820,7 +824,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         let mut innermost_result: Option<&NameBinding> = None;
 
         // Go through all the scopes and try to resolve the name.
-        let mut where_to_resolve = invoc_parent_legacy_scope;
+        let mut where_to_resolve = parent_legacy_scope;
         loop {
             let result = match where_to_resolve {
                 LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
@@ -848,7 +852,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     if let Some(innermost_result) = innermost_result {
                         // Found another solution, if the first one was "weak", report an error.
                         if result.def() != innermost_result.def() &&
-                           innermost_result.may_appear_after(invoc_id, result) {
+                           innermost_result.may_appear_after(parent_expansion, result) {
                             self.ambiguity_errors.push(AmbiguityError {
                                 ident,
                                 b1: innermost_result,
@@ -885,14 +889,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             }
         }
 
-        for &(invoc_id, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() {
+        for &(ident, kind, parent_expansion, parent_legacy_scope, def)
+                in module.legacy_macro_resolutions.borrow().iter() {
             let span = ident.span;
-            let invocation = self.invocations[&invoc_id];
             let legacy_resolution = self.resolve_legacy_scope(
-                ident, invoc_id, invocation.parent_legacy_scope.get(), true
+                ident, Some(kind), parent_expansion, parent_legacy_scope, true
             );
             let resolution = self.resolve_lexical_macro_path_segment(
-                ident, MacroNS, invoc_id, true, true, kind == MacroKind::Attr, span
+                ident, MacroNS, Some(kind), parent_expansion, true, true, span
             );
 
             let check_consistency = |this: &Self, new_def: Def| {
@@ -926,12 +930,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     err.emit();
                 },
                 (Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
-                        if !from_prelude || legacy_binding.may_appear_after(invoc_id, binding) => {
-                    if legacy_binding.def_ignoring_ambiguity() != binding.def_ignoring_ambiguity() {
-                        self.report_ambiguity_error(ident, legacy_binding, binding);
-                    }
+                        if legacy_binding.def() != binding.def_ignoring_ambiguity() &&
+                           (!from_prelude ||
+                            legacy_binding.may_appear_after(parent_expansion, binding)) => {
+                    self.report_ambiguity_error(ident, legacy_binding, binding);
                 },
                 // OK, non-macro-expanded legacy wins over prelude even if defs are different
+                // Also, legacy and modern can co-exist if their defs are same
                 (Some(legacy_binding), Ok(_)) |
                 // OK, unambiguous resolution
                 (Some(legacy_binding), Err(_)) => {
@@ -947,6 +952,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 }
             };
         }
+
+        for &(ident, parent_expansion, parent_legacy_scope)
+                in module.builtin_attrs.borrow().iter() {
+            let resolve_legacy = |this: &mut Self| this.resolve_legacy_scope(
+                ident, Some(MacroKind::Attr), parent_expansion, parent_legacy_scope, true
+            );
+            let resolve_modern = |this: &mut Self| this.resolve_lexical_macro_path_segment(
+                ident, MacroNS, Some(MacroKind::Attr), parent_expansion, true, true, ident.span
+            ).map(|(binding, _)| binding).ok();
+
+            if let Some(binding) = resolve_legacy(self).or_else(|| resolve_modern(self)) {
+                if binding.def_ignoring_ambiguity() !=
+                        Def::NonMacroAttr(NonMacroAttrKind::Builtin) {
+                    let builtin_binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
+                                           ty::Visibility::Public, ident.span, Mark::root())
+                                           .to_name_binding(self.arenas);
+                    self.report_ambiguity_error(ident, binding, builtin_binding);
+                }
+            }
+        }
     }
 
     fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
@@ -958,14 +983,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             None
         // Then check global macros.
         }.or_else(|| {
-            // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
-            let macro_prelude = self.macro_prelude.clone();
-            let names = macro_prelude.iter().filter_map(|(name, binding)| {
-                if binding.get_macro(self).kind() == kind {
-                    Some(name)
-                } else {
-                    None
-                }
+            let names = self.builtin_macros.iter().chain(self.macro_use_prelude.iter())
+                                                  .filter_map(|(name, binding)| {
+                if binding.macro_kind() == Some(kind) { Some(name) } else { None }
             });
             find_best_match_for_name(names, name, None)
         // Then check modules.
@@ -1063,6 +1083,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 self.define(module, ident, MacroNS,
                             (def, vis, item.span, expansion, IsMacroExport));
             } else {
+                if !attr::contains_name(&item.attrs, "rustc_doc_only_macro") {
+                    self.check_reserved_macro_name(ident, MacroNS);
+                }
                 self.unused_macros.insert(def_id);
             }
         } else {
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index f8767fa553f..dfbea0ffe22 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -31,7 +31,7 @@ use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::hygiene::Mark;
 use syntax::symbol::keywords;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::Span;
+use syntax_pos::{MultiSpan, Span};
 
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeMap;
@@ -452,6 +452,16 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
         })
     }
 
+    crate fn check_reserved_macro_name(&self, ident: Ident, ns: Namespace) {
+        // Reserve some names that are not quite covered by the general check
+        // performed on `Resolver::builtin_attrs`.
+        if ns == MacroNS &&
+           (ident.name == "cfg" || ident.name == "cfg_attr" || ident.name == "derive") {
+            self.session.span_err(ident.span,
+                                  &format!("name `{}` is reserved in macro namespace", ident));
+        }
+    }
+
     // Define the name or return the existing binding if there is a collision.
     pub fn try_define(&mut self,
                       module: Module<'a>,
@@ -459,6 +469,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
                       ns: Namespace,
                       binding: &'a NameBinding<'a>)
                       -> Result<(), &'a NameBinding<'a>> {
+        self.check_reserved_macro_name(ident, ns);
         self.update_resolution(module, ident, ns, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
                 if binding.is_glob_import() {
@@ -620,9 +631,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         }
 
         #[derive(Default)]
-        struct UniformPathsCanaryResult {
-            module_scope: Option<Span>,
-            block_scopes: Vec<Span>,
+        struct UniformPathsCanaryResult<'a> {
+            module_scope: Option<&'a NameBinding<'a>>,
+            block_scopes: Vec<&'a NameBinding<'a>>,
         }
         // Collect all tripped `uniform_paths` canaries separately.
         let mut uniform_paths_canaries: BTreeMap<
@@ -632,6 +643,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
 
         let mut errors = false;
         let mut seen_spans = FxHashSet();
+        let mut error_vec = Vec::new();
+        let mut prev_root_id: NodeId = NodeId::new(0);
         for i in 0 .. self.determined_imports.len() {
             let import = self.determined_imports[i];
             let error = self.finalize_import(import);
@@ -661,20 +674,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
 
                 self.per_ns(|_, ns| {
                     if let Some(result) = result[ns].get().ok() {
-                        if let NameBindingKind::Import { directive, .. } = result.kind {
-                            // Skip canaries that resolve to the import itself.
-                            // These come from `use crate_name;`, which isn't really
-                            // ambiguous, as the import can't actually shadow itself.
-                            if directive.id == import.id {
-                                return;
-                            }
-                        }
                         if has_explicit_self {
                             // There should only be one `self::x` (module-scoped) canary.
-                            assert_eq!(canary_results[ns].module_scope, None);
-                            canary_results[ns].module_scope = Some(result.span);
+                            assert!(canary_results[ns].module_scope.is_none());
+                            canary_results[ns].module_scope = Some(result);
                         } else {
-                            canary_results[ns].block_scopes.push(result.span);
+                            canary_results[ns].block_scopes.push(result);
                         }
                     }
                 });
@@ -694,29 +699,59 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 // If the error is a single failed import then create a "fake" import
                 // resolution for it so that later resolve stages won't complain.
                 self.import_dummy_binding(import);
+                if prev_root_id.as_u32() != 0 &&
+                    prev_root_id.as_u32() != import.root_id.as_u32() &&
+                    !error_vec.is_empty(){
+                    // in case of new import line, throw diagnostic message
+                    // for previous line.
+                    let mut empty_vec = vec![];
+                    mem::swap(&mut empty_vec, &mut error_vec);
+                    self.throw_unresolved_import_error(empty_vec, None);
+                }
                 if !seen_spans.contains(&span) {
                     let path = import_path_to_string(&import.module_path[..],
                                                      &import.subclass,
                                                      span);
-                    let error = ResolutionError::UnresolvedImport(Some((span, &path, &err)));
-                    resolve_error(self.resolver, span, error);
+                    error_vec.push((span, path, err));
                     seen_spans.insert(span);
+                    prev_root_id = import.root_id;
                 }
             }
         }
 
+        let uniform_paths_feature = self.session.features_untracked().uniform_paths;
         for ((span, _), (name, results)) in uniform_paths_canaries {
             self.per_ns(|this, ns| {
-                let results = &results[ns];
+                let external_crate = if ns == TypeNS && this.extern_prelude.contains(&name) {
+                    let crate_id =
+                        this.crate_loader.process_path_extern(name, span);
+                    Some(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
+                } else {
+                    None
+                };
+                let result_filter = |result: &&NameBinding| {
+                    // Ignore canaries that resolve to an import of the same crate.
+                    // That is, we allow `use crate_name; use crate_name::foo;`.
+                    if let Some(def_id) = external_crate {
+                        if let Some(module) = result.module() {
+                            if module.normal_ancestor_id == def_id {
+                                return false;
+                            }
+                        }
+                    }
 
-                let has_external_crate =
-                    ns == TypeNS && this.extern_prelude.contains(&name);
+                    true
+                };
+                let module_scope = results[ns].module_scope.filter(result_filter);
+                let block_scopes = || {
+                    results[ns].block_scopes.iter().cloned().filter(result_filter)
+                };
 
                 // An ambiguity requires more than one possible resolution.
                 let possible_resultions =
-                    (has_external_crate as usize) +
-                    (results.module_scope.is_some() as usize) +
-                    (!results.block_scopes.is_empty() as usize);
+                    (external_crate.is_some() as usize) +
+                    (module_scope.is_some() as usize) +
+                    (block_scopes().next().is_some() as usize);
                 if possible_resultions <= 1 {
                     return;
                 }
@@ -726,29 +761,42 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 let msg = format!("`{}` import is ambiguous", name);
                 let mut err = this.session.struct_span_err(span, &msg);
                 let mut suggestion_choices = String::new();
-                if has_external_crate {
+                if external_crate.is_some() {
                     write!(suggestion_choices, "`::{}`", name);
                     err.span_label(span,
                         format!("can refer to external crate `::{}`", name));
                 }
-                if let Some(span) = results.module_scope {
+                if let Some(result) = module_scope {
                     if !suggestion_choices.is_empty() {
                         suggestion_choices.push_str(" or ");
                     }
                     write!(suggestion_choices, "`self::{}`", name);
-                    err.span_label(span,
-                        format!("can refer to `self::{}`", name));
+                    if uniform_paths_feature {
+                        err.span_label(result.span,
+                            format!("can refer to `self::{}`", name));
+                    } else {
+                        err.span_label(result.span,
+                            format!("may refer to `self::{}` in the future", name));
+                    }
                 }
-                for &span in &results.block_scopes {
-                    err.span_label(span,
+                for result in block_scopes() {
+                    err.span_label(result.span,
                         format!("shadowed by block-scoped `{}`", name));
                 }
                 err.help(&format!("write {} explicitly instead", suggestion_choices));
-                err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`");
+                if uniform_paths_feature {
+                    err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`");
+                } else {
+                    err.note("in the future, `#![feature(uniform_paths)]` may become the default");
+                }
                 err.emit();
             });
         }
 
+        if !error_vec.is_empty() {
+            self.throw_unresolved_import_error(error_vec.clone(), None);
+        }
+
         // Report unresolved imports only if no hard error was already reported
         // to avoid generating multiple errors on the same import.
         if !errors {
@@ -756,14 +804,37 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 if import.is_uniform_paths_canary {
                     continue;
                 }
-
-                let error = ResolutionError::UnresolvedImport(None);
-                resolve_error(self.resolver, import.span, error);
+                self.throw_unresolved_import_error(error_vec, Some(MultiSpan::from(import.span)));
                 break;
             }
         }
     }
 
+    fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
+                                     span: Option<MultiSpan>) {
+        let max_span_label_msg_count = 10;  // upper limit on number of span_label message.
+        let (span,msg) = match error_vec.is_empty() {
+            true => (span.unwrap(), "unresolved import".to_string()),
+            false => {
+                let span = MultiSpan::from_spans(error_vec.clone().into_iter()
+                                    .map(|elem: (Span, String, String)| { elem.0 }
+                                    ).collect());
+                let path_vec: Vec<String> = error_vec.clone().into_iter()
+                                .map(|elem: (Span, String, String)| { format!("`{}`", elem.1) }
+                                ).collect();
+                let path = path_vec.join(", ");
+                let msg = format!("unresolved import{} {}",
+                                if path_vec.len() > 1 { "s" } else { "" },  path);
+                (span, msg)
+            }
+        };
+        let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
+        for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
+            err.span_label(span_error.0, span_error.2);
+        }
+        err.emit();
+    }
+
     /// Attempts to resolve the given import, returning true if its resolution is determined.
     /// If successful, the resolved bindings are written into the module.
     fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
@@ -930,11 +1001,15 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
             _ => unreachable!(),
         };
 
+        // Do not record uses from canaries, to avoid interfering with other
+        // diagnostics or suggestions that rely on some items not being used.
+        let record_used = !directive.is_uniform_paths_canary;
+
         let mut all_ns_err = true;
         self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
             if let Ok(binding) = result[ns].get() {
                 all_ns_err = false;
-                if this.record_use(ident, ns, binding) {
+                if record_used && this.record_use(ident, ns, binding) {
                     if let ModuleOrUniformRoot::Module(module) = module {
                         this.resolution(module, ident, ns).borrow_mut().binding =
                             Some(this.dummy_binding);
@@ -946,7 +1021,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         if all_ns_err {
             let mut all_ns_failed = true;
             self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
-                match this.resolve_ident_in_module(module, ident, ns, true, span) {
+                match this.resolve_ident_in_module(module, ident, ns, record_used, span) {
                     Ok(_) => all_ns_failed = false,
                     _ => {}
                 }
diff --git a/src/librustc_target/abi/call/amdgpu.rs b/src/librustc_target/abi/call/amdgpu.rs
new file mode 100644
index 00000000000..62462f04d8f
--- /dev/null
+++ b/src/librustc_target/abi/call/amdgpu.rs
@@ -0,0 +1,42 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use abi::call::{ArgType, FnType, };
+use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+
+fn classify_ret_ty<'a, Ty, C>(_tuncx: C, ret: &mut ArgType<'a, Ty>)
+  where Ty: TyLayoutMethods<'a, C> + Copy,
+        C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+  ret.extend_integer_width_to(32);
+}
+
+fn classify_arg_ty<'a, Ty, C>(_cx: C, arg: &mut ArgType<'a, Ty>)
+  where Ty: TyLayoutMethods<'a, C> + Copy,
+        C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+  arg.extend_integer_width_to(32);
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>)
+  where Ty: TyLayoutMethods<'a, C> + Copy,
+        C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+  if !fty.ret.is_ignore() {
+    classify_ret_ty(cx, &mut fty.ret);
+  }
+
+  for arg in &mut fty.args {
+    if arg.is_ignore() {
+      continue;
+    }
+    classify_arg_ty(cx, arg);
+  }
+}
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
index 78ed4b2d615..788497a378f 100644
--- a/src/librustc_target/abi/call/mod.rs
+++ b/src/librustc_target/abi/call/mod.rs
@@ -13,6 +13,7 @@ use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
 use spec::HasTargetSpec;
 
 mod aarch64;
+mod amdgpu;
 mod arm;
 mod asmjs;
 mod hexagon;
@@ -503,6 +504,7 @@ impl<'a, Ty> FnType<'a, Ty> {
                 x86_64::compute_abi_info(cx, self);
             },
             "aarch64" => aarch64::compute_abi_info(cx, self),
+            "amdgpu" => amdgpu::compute_abi_info(cx, self),
             "arm" => arm::compute_abi_info(cx, self),
             "mips" => mips::compute_abi_info(cx, self),
             "mips64" => mips64::compute_abi_info(cx, self),
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 972c2f0e15c..45a5e5115a3 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1257,9 +1257,11 @@ impl DocFolder for Cache {
         // Collect all the implementors of traits.
         if let clean::ImplItem(ref i) = item.inner {
             if let Some(did) = i.trait_.def_id() {
-                self.implementors.entry(did).or_default().push(Impl {
-                    impl_item: item.clone(),
-                });
+                if i.blanket_impl.is_none() {
+                    self.implementors.entry(did).or_default().push(Impl {
+                        impl_item: item.clone(),
+                    });
+                }
             }
         }
 
@@ -2931,7 +2933,6 @@ fn item_trait(
 
 
         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
-            .filter(|i| i.inner_impl().blanket_impl.is_none())
             .partition(|i| i.inner_impl().synthetic);
 
         if !foreign.is_empty() {
@@ -2941,17 +2942,14 @@ fn item_trait(
                 </h2>
             ")?;
 
-            let mut foreign_cache = FxHashSet();
             for implementor in foreign {
-                if foreign_cache.insert(implementor.inner_impl().to_string()) {
-                    let assoc_link = AssocItemLink::GotoSource(
-                        implementor.impl_item.def_id,
-                        &implementor.inner_impl().provided_trait_methods
-                    );
-                    render_impl(w, cx, &implementor, assoc_link,
-                                RenderMode::Normal, implementor.impl_item.stable_since(), false,
-                                None)?;
-                }
+                let assoc_link = AssocItemLink::GotoSource(
+                    implementor.impl_item.def_id,
+                    &implementor.inner_impl().provided_trait_methods
+                );
+                render_impl(w, cx, &implementor, assoc_link,
+                            RenderMode::Normal, implementor.impl_item.stable_since(), false,
+                            None)?;
             }
         }
 
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 3e54b502234..804d43f4fc6 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -166,14 +166,14 @@ impl DefaultResizePolicy {
 // Our hash generation scheme consists of generating a 64-bit hash and
 // truncating the most significant bits. When moving to the new table, we
 // simply introduce a new bit to the front of the hash. Therefore, if an
-// elements has ideal index i in the old table, it can have one of two ideal
+// element has ideal index i in the old table, it can have one of two ideal
 // locations in the new table. If the new bit is 0, then the new ideal index
 // is i. If the new bit is 1, then the new ideal index is n + i. Intuitively,
 // we are producing two independent tables of size n, and for each element we
 // independently choose which table to insert it into with equal probability.
-// However the rather than wrapping around themselves on overflowing their
-// indexes, the first table overflows into the first, and the first into the
-// second. Visually, our new table will look something like:
+// However, rather than wrapping around themselves on overflowing their
+// indexes, the first table overflows into the second, and the second into the
+// first. Visually, our new table will look something like:
 //
 // [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy]
 //
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 2b87094926c..372f3e83e3d 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -33,7 +33,7 @@ use sys;
 /// type is a static guarantee that the underlying bytes contain no interior 0
 /// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
 ///
-/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former
+/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former
 /// in each pair are owned strings; the latter are borrowed
 /// references.
 ///
@@ -88,6 +88,7 @@ use sys;
 /// [slice.len]: ../primitive.slice.html#method.len
 /// [`Deref`]: ../ops/trait.Deref.html
 /// [`CStr`]: struct.CStr.html
+/// [`&CStr`]: struct.CStr.html
 ///
 /// # Examples
 ///
@@ -137,7 +138,7 @@ pub struct CString {
 /// converted to a Rust [`&str`] by performing UTF-8 validation, or
 /// into an owned [`CString`].
 ///
-/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
 /// in each pair are borrowed references; the latter are owned
 /// strings.
 ///
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index b83f3fbe7a5..278ee7951b3 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -1330,7 +1330,8 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
 ///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait BufRead: Read {
-    /// Fills the internal buffer of this object, returning the buffer contents.
+    /// Returns the contents of the internal buffer, filling it with more data
+    /// from the inner reader if it is empty.
     ///
     /// This function is a lower-level call. It needs to be paired with the
     /// [`consume`] method to function properly. When calling this
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 4278926b042..5c9e88dc57c 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -307,7 +307,7 @@
 #![feature(doc_cfg)]
 #![feature(doc_masked)]
 #![feature(doc_spotlight)]
-#![cfg_attr(windows, feature(used))]
+#![cfg_attr(all(windows, stage0), feature(used))]
 #![feature(doc_alias)]
 #![feature(doc_keyword)]
 #![feature(panic_info_message)]
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 0e059bc4a6c..07c3e578e5b 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -721,17 +721,15 @@ pub trait Resolver {
     fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
                                             derives: &[Mark]);
     fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
-    fn add_unshadowable_attr(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
 
     fn resolve_imports(&mut self);
     // Resolves attribute and derive legacy macros from `#![plugin(..)]`.
     fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>, allow_derive: bool)
                               -> Option<Attribute>;
 
-    fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
+    fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
                                 -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
-
-    fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+    fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
                           derives_in_scope: &[ast::Path], force: bool)
                           -> Result<Lrc<SyntaxExtension>, Determinacy>;
 
@@ -761,16 +759,15 @@ impl Resolver for DummyResolver {
     fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
                                             _derives: &[Mark]) {}
     fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
-    fn add_unshadowable_attr(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
 
     fn resolve_imports(&mut self) {}
     fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool)
                               -> Option<Attribute> { None }
-    fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _scope: Mark, _force: bool)
+    fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _invoc_id: Mark, _force: bool)
                                 -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
         Err(Determinacy::Determined)
     }
-    fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _scope: Mark,
+    fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark,
                           _derives_in_scope: &[ast::Path], _force: bool)
                           -> Result<Lrc<SyntaxExtension>, Determinacy> {
         Err(Determinacy::Determined)
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 3bb19121ee3..7b4e1814a33 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1074,6 +1074,21 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         self.collect(kind, InvocationKind::Attr { attr, traits, item })
     }
 
+    fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
+        let attr = attrs.iter()
+                        .position(|a| !attr::is_known(a) && !is_builtin_attr(a))
+                        .map(|i| attrs.remove(i));
+        if let Some(attr) = &attr {
+            if !self.cx.ecfg.enable_custom_inner_attributes() &&
+               attr.style == ast::AttrStyle::Inner && attr.path != "test" {
+                emit_feature_err(&self.cx.parse_sess, "custom_inner_attributes",
+                                 attr.span, GateIssue::Language,
+                                 "non-builtin inner attributes are unstable");
+            }
+        }
+        attr
+    }
+
     /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
     fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T)
         where T: HasAttrs,
@@ -1087,7 +1102,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 return attrs;
             }
 
-            attr = find_attr_invoc(&mut attrs);
+            attr = self.find_attr_invoc(&mut attrs);
             traits = collect_derives(&mut self.cx, &mut attrs);
             attrs
         });
@@ -1108,7 +1123,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 return attrs;
             }
 
-            attr = find_attr_invoc(&mut attrs);
+            attr = self.find_attr_invoc(&mut attrs);
             attrs
         });
 
@@ -1145,12 +1160,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     }
 }
 
-pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
-    attrs.iter()
-         .position(|a| !attr::is_known(a) && !is_builtin_attr(a))
-         .map(|i| attrs.remove(i))
-}
-
 impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
         let mut expr = self.cfg.configure_expr(expr).into_inner();
@@ -1582,6 +1591,12 @@ impl<'feat> ExpansionConfig<'feat> {
         fn proc_macro_expr = proc_macro_expr,
         fn proc_macro_non_items = proc_macro_non_items,
     }
+
+    fn enable_custom_inner_attributes(&self) -> bool {
+        self.features.map_or(false, |features| {
+            features.custom_inner_attributes || features.custom_attribute || features.rustc_attrs
+        })
+    }
 }
 
 // A Marker adds the given mark to the syntax context.
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index e912482cf58..2b4daa6440c 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -37,7 +37,7 @@ use visit::{self, FnKind, Visitor};
 use parse::ParseSess;
 use symbol::{keywords, Symbol};
 
-use std::{env, path};
+use std::{env};
 
 macro_rules! set {
     // The const_fn feature also enables the min_const_fn feature, because `min_const_fn` allows
@@ -349,9 +349,6 @@ declare_features! (
     // Allows the `try {...}` expression
     (active, try_blocks, "1.29.0", Some(31436), None),
 
-    // Used to preserve symbols (see llvm.used)
-    (active, used, "1.18.0", Some(40289), None),
-
     // Allows module-level inline assembly by way of global_asm!()
     (active, global_asm, "1.18.0", Some(35119), None),
 
@@ -409,9 +406,6 @@ declare_features! (
     // Resolve absolute paths as paths from other crates
     (active, extern_absolute_paths, "1.24.0", Some(44660), Some(Edition::Edition2018)),
 
-    // `foo.rs` as an alternative to `foo/mod.rs`
-    (active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
-
     // `extern` in paths
     (active, extern_in_paths, "1.23.0", Some(44660), None),
 
@@ -518,6 +512,9 @@ declare_features! (
     // #![test_runner]
     // #[test_case]
     (active, custom_test_frameworks, "1.30.0", Some(50297), None),
+
+    // Non-builtin attributes in inner attribute position
+    (active, custom_inner_attributes, "1.30.0", Some(38356), None),
 );
 
 declare_features! (
@@ -660,6 +657,8 @@ declare_features! (
     (accepted, repr_transparent, "1.28.0", Some(43036), None),
     // Defining procedural macros in `proc-macro` crates
     (accepted, proc_macro, "1.29.0", Some(38356), None),
+    // `foo.rs` as an alternative to `foo/mod.rs`
+    (accepted, non_modrs_mods, "1.30.0", Some(44660), None),
     // Allows use of the :vis macro fragment specifier
     (accepted, macro_vis_matcher, "1.30.0", Some(41022), None),
     // Allows importing and reexporting macros with `use`,
@@ -674,6 +673,9 @@ declare_features! (
     // Allows all literals in attribute lists and values of key-value pairs.
     (accepted, attr_literals, "1.30.0", Some(34981), None),
     (accepted, panic_handler, "1.30.0", Some(44489), None),
+    // Used to preserve symbols (see llvm.used)
+    (accepted, used, "1.30.0", Some(40289), None),
+
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
@@ -1068,10 +1070,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                   "unwind_attributes",
                                   "#[unwind] is experimental",
                                   cfg_fn!(unwind_attributes))),
-    ("used", Whitelisted, Gated(
-        Stability::Unstable, "used",
-        "the `#[used]` attribute is an experimental feature",
-        cfg_fn!(used))),
+    ("used", Whitelisted, Ungated),
 
     // used in resolve
     ("prelude_import", Whitelisted, Gated(Stability::Unstable,
@@ -1498,31 +1497,6 @@ impl<'a> PostExpansionVisitor<'a> {
     }
 }
 
-impl<'a> PostExpansionVisitor<'a> {
-    fn whole_crate_feature_gates(&mut self, _krate: &ast::Crate) {
-        for &(ident, span) in &*self.context.parse_sess.non_modrs_mods.borrow() {
-            if !span.allows_unstable() {
-                let cx = &self.context;
-                let level = GateStrength::Hard;
-                let has_feature = cx.features.non_modrs_mods;
-                let name = "non_modrs_mods";
-                debug!("gate_feature(feature = {:?}, span = {:?}); has? {}",
-                        name, span, has_feature);
-
-                if !has_feature && !span.allows_unstable() {
-                    leveled_feature_err(
-                        cx.parse_sess, name, span, GateIssue::Language,
-                        "mod statements in non-mod.rs files are unstable", level
-                    )
-                    .help(&format!("on stable builds, rename this file to {}{}mod.rs",
-                                   ident, path::MAIN_SEPARATOR))
-                    .emit();
-                }
-            }
-        }
-    }
-}
-
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
         if !attr.span.allows_unstable() {
@@ -2092,7 +2066,6 @@ pub fn check_crate(krate: &ast::Crate,
     };
 
     let visitor = &mut PostExpansionVisitor { context: &ctx };
-    visitor.whole_crate_feature_gates(krate);
     visit::walk_crate(visitor, krate);
 }
 
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index b7e8a880e7e..aa47d5bf669 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -66,10 +66,10 @@ pub struct StringReader<'a> {
     /// The raw source span which *does not* take `override_span` into account
     span_src_raw: Span,
     open_braces: Vec<(token::DelimToken, Span)>,
-    /// The type and spans for all braces that have different indentation.
+    /// The type and spans for all braces
     ///
     /// Used only for error recovery when arriving to EOF with mismatched braces.
-    suspicious_open_spans: Vec<(token::DelimToken, Span, Span)>,
+    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
     crate override_span: Option<Span>,
     last_unclosed_found_span: Option<Span>,
 }
@@ -220,7 +220,7 @@ impl<'a> StringReader<'a> {
             span: syntax_pos::DUMMY_SP,
             span_src_raw: syntax_pos::DUMMY_SP,
             open_braces: Vec::new(),
-            suspicious_open_spans: Vec::new(),
+            matching_delim_spans: Vec::new(),
             override_span,
             last_unclosed_found_span: None,
         }
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index 9e08fa232f1..8047ab01465 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -44,6 +44,7 @@ impl<'a> StringReader<'a> {
     }
 
     fn parse_token_tree(&mut self) -> PResult<'a, TokenStream> {
+        let sm = self.sess.source_map();
         match self.token {
             token::Eof => {
                 let msg = "this file contains an un-closed delimiter";
@@ -53,20 +54,25 @@ impl<'a> StringReader<'a> {
                 }
 
                 if let Some((delim, _)) = self.open_braces.last() {
-                    if let Some((d, open_sp, close_sp)) = self.suspicious_open_spans.iter()
-                        .filter(|(d, _, _)| delim == d)
-                        .next()  // these are in reverse order as they get inserted on close, but
-                    {            // we want the last open/first close
-                        if d == delim {
-                            err.span_label(
-                                *open_sp,
-                                "this delimiter might not be properly closed...",
-                            );
-                            err.span_label(
-                                *close_sp,
-                                "...as it matches this but it has different indentation",
-                            );
+                    if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter()
+                        .filter(|(d, open_sp, close_sp)| {
+
+                        if let Some(close_padding) = sm.span_to_margin(*close_sp) {
+                            if let Some(open_padding) = sm.span_to_margin(*open_sp) {
+                                return delim == d && close_padding != open_padding;
+                            }
                         }
+                        false
+                        }).next()  // these are in reverse order as they get inserted on close, but
+                    {              // we want the last open/first close
+                        err.span_label(
+                            *open_sp,
+                            "this delimiter might not be properly closed...",
+                        );
+                        err.span_label(
+                            *close_sp,
+                            "...as it matches this but it has different indentation",
+                        );
                     }
                 }
                 Err(err)
@@ -87,20 +93,11 @@ impl<'a> StringReader<'a> {
                 // Expand to cover the entire delimited token tree
                 let delim_span = DelimSpan::from_pair(pre_span, self.span);
 
-                let sm = self.sess.source_map();
                 match self.token {
                     // Correct delimiter.
                     token::CloseDelim(d) if d == delim => {
                         let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
-                        if let Some(current_padding) = sm.span_to_margin(self.span) {
-                            if let Some(padding) = sm.span_to_margin(open_brace_span) {
-                                if current_padding != padding {
-                                    self.suspicious_open_spans.push(
-                                        (open_brace, open_brace_span, self.span),
-                                    );
-                                }
-                            }
-                        }
+                        self.matching_delim_spans.push((open_brace, open_brace_span, self.span));
                         // Parse the close delimiter.
                         self.real_token();
                     }
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index e16f3b1ccb3..88af4a73a15 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -72,18 +72,6 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
                          enable_quotes: bool) {
     deriving::register_builtin_derives(resolver);
 
-    {
-        let mut register_unshadowable = |name, ext| {
-            resolver.add_unshadowable_attr(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
-        };
-
-        register_unshadowable(Symbol::intern("test"),
-            MultiModifier(Box::new(test::expand_test)));
-
-        register_unshadowable(Symbol::intern("bench"),
-            MultiModifier(Box::new(test::expand_bench)));
-    }
-
     let mut register = |name, ext| {
         resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
     };
@@ -147,6 +135,8 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
     }
 
     register(Symbol::intern("test_case"), MultiModifier(Box::new(test_case::expand)));
+    register(Symbol::intern("test"), MultiModifier(Box::new(test::expand_test)));
+    register(Symbol::intern("bench"), MultiModifier(Box::new(test::expand_bench)));
 
     // format_args uses `unstable` things internally.
     register(Symbol::intern("format_args"),
diff --git a/src/llvm b/src/llvm
-Subproject 2a1cdeadd3ea8e1eba9cc681037b83f07332763
+Subproject 5a081f0363340dd895d0958955d0c84661f60f0
diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger
index 24a384fceb8..29b7d508f1c 100644
--- a/src/rustllvm/llvm-rebuild-trigger
+++ b/src/rustllvm/llvm-rebuild-trigger
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2018-08-22
+2018-09-11
diff --git a/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs b/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs
index 3cb565c1ede..cf2522be922 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs
@@ -11,6 +11,8 @@
 // aux-build:attribute-with-error.rs
 // ignore-stage1
 
+#![feature(custom_inner_attributes)]
+
 extern crate attribute_with_error;
 
 use attribute_with_error::foo;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
index 52d7afb26ad..e0922c452b5 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs
@@ -13,6 +13,8 @@
 // FIXME: https://github.com/rust-lang/rust/issues/41430
 // This is a temporary regression test for the ICE reported in #41211
 
+#![feature(custom_inner_attributes)]
+
 #![emit_unchanged]
 //~^ ERROR attribute `emit_unchanged` is currently unknown to the compiler
 extern crate issue_41211;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
index 5cf65103ba3..c07e6e31d62 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
@@ -22,7 +22,7 @@ extern crate proc_macro_gates as foo;
 use foo::*;
 
 fn _test_inner() {
-    #![a] // OK
+    #![a] //~ ERROR: non-builtin inner attributes are unstable
 }
 
 #[a] //~ ERROR: custom attributes cannot be applied to modules
@@ -30,6 +30,7 @@ mod _test2 {}
 
 mod _test2_inner {
     #![a] //~ ERROR: custom attributes cannot be applied to modules
+          //~| ERROR: non-builtin inner attributes are unstable
 }
 
 #[a = y] //~ ERROR: must only be followed by a delimiter token
diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs
index 957cb336d9e..097cd665375 100644
--- a/src/test/incremental/hashes/let_expressions.rs
+++ b/src/test/incremental/hashes/let_expressions.rs
@@ -49,7 +49,7 @@ pub fn add_type() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,TypeckTables,MirValidated")]
+    except="HirBody,TypeckTables,MirValidated,MirOptimized")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_type() {
     let _x: u32 = 2u32;
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index 54b7a3821ca..f04d4328929 100644
--- a/src/test/mir-opt/basic_assignment.rs
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -19,9 +19,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// check that codegen of assignment expressions is sane. Assignments
-// tend to be absent in simple code, so subtle breakage in them can
-// leave a quite hard-to-find trail of destruction.
+// Check codegen for assignments (`a = b`) where the left-hand-side is
+// not yet initialized. Assignments tend to be absent in simple code,
+// so subtle breakage in them can leave a quite hard-to-find trail of
+// destruction.
 
 // ignore-tidy-linelength
 
@@ -29,60 +30,42 @@ fn main() {
     let nodrop_x = false;
     let nodrop_y;
 
+    // Since boolean does not require drop, this can be a simple
+    // assignment:
     nodrop_y = nodrop_x;
 
     let drop_x : Option<Box<u32>> = None;
     let drop_y;
 
+    // Since the type of `drop_y` has drop, we generate a `replace`
+    // terminator:
     drop_y = drop_x;
 }
 
 // END RUST SOURCE
 // START rustc.main.SimplifyCfg-initial.after.mir
-//     bb0: {
-//         StorageLive(_1);
-//         _1 = const false;
-//         StorageLive(_2);
-//         StorageLive(_3);
-//         _3 = _1;
-//         _2 = move _3;
-//         StorageDead(_3);
-//         StorageLive(_4);
-//         UserAssertTy(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }, _4);
-//         _4 = std::option::Option<std::boxed::Box<u32>>::None;
-//         StorageLive(_5);
-//         StorageLive(_6);
-//         _6 = move _4;
-//         replace(_5 <-move _6) -> [return: bb2, unwind: bb5];
-//     }
-//     bb1: {
-//         resume;
-//     }
-//     bb2: {
-//         drop(_6) -> [return: bb6, unwind: bb4];
-//     }
-//     bb3: {
-//         drop(_4) -> bb1;
-//     }
-//     bb4: {
-//         drop(_5) -> bb3;
-//     }
-//     bb5: {
-//         drop(_6) -> bb4;
-//     }
-//     bb6: {
-//         StorageDead(_6);
-//         _0 = ();
-//         drop(_5) -> [return: bb7, unwind: bb3];
-//     }
-//     bb7: {
-//         StorageDead(_5);
-//         drop(_4) -> [return: bb8, unwind: bb1];
-//     }
-//     bb8: {
-//         StorageDead(_4);
-//         StorageDead(_2);
-//         StorageDead(_1);
-//         return;
-//     }
+//    bb0: {
+//        StorageLive(_1);
+//        _1 = const false;
+//        StorageLive(_2);
+//        StorageLive(_3);
+//        _3 = _1;
+//        _2 = move _3;
+//        StorageDead(_3);
+//        StorageLive(_4);
+//        _4 = std::option::Option<std::boxed::Box<u32>>::None;
+//        AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
+//        StorageLive(_5);
+//        StorageLive(_6);
+//        _6 = move _4;
+//        replace(_5 <- move _6) -> [return: bb2, unwind: bb5];
+//    }
+//    ...
+//    bb2: {
+//        drop(_6) -> [return: bb6, unwind: bb4];
+//    }
+//    ...
+//    bb5: {
+//        drop(_6) -> bb4;
+//    }
 // END rustc.main.SimplifyCfg-initial.after.mir
diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs
deleted file mode 100644
index 8a7ea8962fc..00000000000
--- a/src/test/mir-opt/nll/reborrow-basic.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Basic test for reborrow constraints: the region (`R5`) that appears
-// in the type of `r_a` must outlive the region (`R7`) that appears in
-// the type of `r_b`
-
-// compile-flags:-Zborrowck=mir -Zverbose
-//                              ^^^^^^^^^ force compiler to dump more region information
-
-#![allow(warnings)]
-
-fn use_x(_: &mut i32) -> bool { true }
-
-fn main() {
-    let mut foo: i32     = 22;
-    let r_a: &mut i32 = &mut foo;
-    let r_b: &mut i32 = &mut *r_a;
-    use_x(r_b);
-}
-
-// END RUST SOURCE
-// START rustc.main.nll.0.mir
-// | '_#7r    | U0 | {bb0[4], bb0[8..=17]}
-// ...
-// | '_#9r    | U0 | {bb0[10], bb0[14..=17]}
-// ...
-// let _4: &'_#9r mut i32;
-// ...
-// let _2: &'_#7r mut i32;
-// END rustc.main.nll.0.mir
diff --git a/src/test/run-make-fulldeps/used/used.rs b/src/test/run-make-fulldeps/used/used.rs
index 186cd0fdf5e..6992dd94af3 100644
--- a/src/test/run-make-fulldeps/used/used.rs
+++ b/src/test/run-make-fulldeps/used/used.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![crate_type = "lib"]
-#![feature(used)]
 
 #[used]
 static FOO: u32 = 0;
diff --git a/src/test/run-pass/.gitattributes b/src/test/run-pass/.gitattributes
index 46db548a8c4..c6a6f23074d 100644
--- a/src/test/run-pass/.gitattributes
+++ b/src/test/run-pass/.gitattributes
@@ -1,2 +1 @@
 lexer-crlf-line-endings-string-literal-doc-comment.rs -text
-issue-16278.rs -text
diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs
index 46f22845907..f692f57abb9 100644
--- a/src/test/run-pass/async-await.rs
+++ b/src/test/run-pass/async-await.rs
@@ -67,6 +67,13 @@ fn async_block(x: u8) -> impl Future<Output = u8> {
     }
 }
 
+fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+    async move {
+        await!(wake_and_yield_once());
+        *x
+    }
+}
+
 fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
     async move {
         let future = async {
@@ -94,6 +101,23 @@ async fn async_fn_with_borrow(x: &u8) -> u8 {
     *x
 }
 
+async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+
+fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+    async move {
+        await!(wake_and_yield_once());
+        *x
+    }
+}
+
+async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+
 fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
     async move {
         await!(async_fn_with_borrow(&y))
@@ -138,16 +162,43 @@ where
 
 fn main() {
     macro_rules! test {
-        ($($fn_name:ident,)*) => { $(
+        ($($fn_name:expr,)*) => { $(
             test_future_yields_once_then_returns($fn_name);
         )* }
     }
 
+    macro_rules! test_with_borrow {
+        ($($fn_name:expr,)*) => { $(
+            test_future_yields_once_then_returns(|x| {
+                async move {
+                    await!($fn_name(&x))
+                }
+            });
+        )* }
+    }
+
     test! {
         async_block,
         async_nonmove_block,
         async_closure,
         async_fn,
         async_fn_with_internal_borrow,
+        |x| {
+            async move {
+                unsafe { await!(unsafe_async_fn(x)) }
+            }
+        },
+    }
+
+    test_with_borrow! {
+        async_block_with_borrow_named_lifetime,
+        async_fn_with_borrow,
+        async_fn_with_borrow_named_lifetime,
+        async_fn_with_impl_future_named_lifetime,
+        |x| {
+            async move {
+                await!(async_fn_with_named_lifetime_multiple_args(x, x))
+            }
+        },
     }
 }
diff --git a/src/test/ui/feature-gates/feature-gate-used.rs b/src/test/rustdoc/auxiliary/issue-53689.rs
index 68679d7dac8..7b7f9013ca3 100644
--- a/src/test/ui/feature-gates/feature-gate-used.rs
+++ b/src/test/rustdoc/auxiliary/issue-53689.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,8 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[used]
-fn foo() {}
-//~^^ ERROR the `#[used]` attribute is an experimental feature
-
-fn main() {}
+pub struct MyStruct;
diff --git a/src/test/rustdoc/issue-53689.rs b/src/test/rustdoc/issue-53689.rs
new file mode 100644
index 00000000000..bfe5adf8888
--- /dev/null
+++ b/src/test/rustdoc/issue-53689.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-53689.rs
+
+#![crate_name = "foo"]
+
+extern crate issue_53689;
+
+// @has foo/trait.MyTrait.html
+// @!has - 'MyStruct'
+// @count - '//*[code="impl<T> MyTrait for T"]' 1
+pub trait MyTrait {}
+
+impl<T> MyTrait for T {}
+
+mod a {
+    pub use issue_53689::MyStruct;
+}
diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs
new file mode 100644
index 00000000000..6a47e50f62d
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs
@@ -0,0 +1,20 @@
+// aux-build:builtin-attrs.rs
+// compile-flags:--test
+
+#![feature(decl_macro, test)]
+
+extern crate test;
+extern crate builtin_attrs;
+use builtin_attrs::{test, bench};
+
+#[test] // OK, shadowed
+fn test() {}
+
+#[bench] // OK, shadowed
+fn bench(b: &mut test::Bencher) {}
+
+fn not_main() {
+    Test;
+    Bench;
+    NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
+}
diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr
new file mode 100644
index 00000000000..db07055b6a1
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `NonExistent` in this scope
+  --> $DIR/ambiguous-builtin-attrs-test.rs:19:5
+   |
+LL |     NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
+   |     ^^^^^^^^^^^ 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-fulldeps/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs
new file mode 100644
index 00000000000..9f4f0abf324
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs
@@ -0,0 +1,31 @@
+// aux-build:builtin-attrs.rs
+
+#![feature(decl_macro)] //~ ERROR `feature` is ambiguous
+
+extern crate builtin_attrs;
+use builtin_attrs::{test, bench};
+use builtin_attrs::*;
+
+#[repr(C)] //~ ERROR `repr` is ambiguous
+struct S;
+#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
+struct SCond;
+
+#[test] // OK, shadowed
+fn test() {}
+
+#[bench] // OK, shadowed
+fn bench() {}
+
+fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous
+    match 0u8 {
+        #[repr(C)] //~ ERROR `repr` is ambiguous
+        _ => {}
+    }
+}
+
+fn main() {
+    Test;
+    Bench;
+    NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
+}
diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr
new file mode 100644
index 00000000000..ea867faf47b
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr
@@ -0,0 +1,100 @@
+error[E0659]: `repr` is ambiguous
+  --> $DIR/ambiguous-builtin-attrs.rs:9:3
+   |
+LL | #[repr(C)] //~ ERROR `repr` is ambiguous
+   |   ^^^^ ambiguous name
+   |
+note: `repr` could refer to the name imported here
+  --> $DIR/ambiguous-builtin-attrs.rs:7:5
+   |
+LL | use builtin_attrs::*;
+   |     ^^^^^^^^^^^^^^^^
+note: `repr` could also refer to the name defined here
+  --> $DIR/ambiguous-builtin-attrs.rs:9:3
+   |
+LL | #[repr(C)] //~ ERROR `repr` is ambiguous
+   |   ^^^^
+   = note: consider adding an explicit import of `repr` to disambiguate
+
+error[E0659]: `repr` is ambiguous
+  --> $DIR/ambiguous-builtin-attrs.rs:11:19
+   |
+LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
+   |                   ^^^^ ambiguous name
+   |
+note: `repr` could refer to the name imported here
+  --> $DIR/ambiguous-builtin-attrs.rs:7:5
+   |
+LL | use builtin_attrs::*;
+   |     ^^^^^^^^^^^^^^^^
+note: `repr` could also refer to the name defined here
+  --> $DIR/ambiguous-builtin-attrs.rs:11:19
+   |
+LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
+   |                   ^^^^
+   = note: consider adding an explicit import of `repr` to disambiguate
+
+error[E0659]: `repr` is ambiguous
+  --> $DIR/ambiguous-builtin-attrs.rs:20:34
+   |
+LL | fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous
+   |                                  ^^^^ ambiguous name
+   |
+note: `repr` could refer to the name imported here
+  --> $DIR/ambiguous-builtin-attrs.rs:7:5
+   |
+LL | use builtin_attrs::*;
+   |     ^^^^^^^^^^^^^^^^
+note: `repr` could also refer to the name defined here
+  --> $DIR/ambiguous-builtin-attrs.rs:20:34
+   |
+LL | fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous
+   |                                  ^^^^
+   = note: consider adding an explicit import of `repr` to disambiguate
+
+error[E0659]: `repr` is ambiguous
+  --> $DIR/ambiguous-builtin-attrs.rs:22:11
+   |
+LL |         #[repr(C)] //~ ERROR `repr` is ambiguous
+   |           ^^^^ ambiguous name
+   |
+note: `repr` could refer to the name imported here
+  --> $DIR/ambiguous-builtin-attrs.rs:7:5
+   |
+LL | use builtin_attrs::*;
+   |     ^^^^^^^^^^^^^^^^
+note: `repr` could also refer to the name defined here
+  --> $DIR/ambiguous-builtin-attrs.rs:22:11
+   |
+LL |         #[repr(C)] //~ ERROR `repr` is ambiguous
+   |           ^^^^
+   = note: consider adding an explicit import of `repr` to disambiguate
+
+error[E0659]: `feature` is ambiguous
+  --> $DIR/ambiguous-builtin-attrs.rs:3:4
+   |
+LL | #![feature(decl_macro)] //~ ERROR `feature` is ambiguous
+   |    ^^^^^^^ ambiguous name
+   |
+note: `feature` could refer to the name imported here
+  --> $DIR/ambiguous-builtin-attrs.rs:7:5
+   |
+LL | use builtin_attrs::*;
+   |     ^^^^^^^^^^^^^^^^
+note: `feature` could also refer to the name defined here
+  --> $DIR/ambiguous-builtin-attrs.rs:3:4
+   |
+LL | #![feature(decl_macro)] //~ ERROR `feature` is ambiguous
+   |    ^^^^^^^
+   = note: consider adding an explicit import of `feature` to disambiguate
+
+error[E0425]: cannot find value `NonExistent` in this scope
+  --> $DIR/ambiguous-builtin-attrs.rs:30:5
+   |
+LL |     NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
+   |     ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to 6 previous errors
+
+Some errors occurred: E0425, E0659.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs
new file mode 100644
index 00000000000..e18ca57aab1
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs
@@ -0,0 +1,36 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn feature(_: TokenStream, input: TokenStream) -> TokenStream {
+    input
+}
+
+#[proc_macro_attribute]
+pub fn repr(_: TokenStream, input: TokenStream) -> TokenStream {
+    input
+}
+
+#[proc_macro_attribute]
+pub fn test(_: TokenStream, input: TokenStream) -> TokenStream {
+    "struct Test;".parse().unwrap()
+}
+
+#[proc_macro_attribute]
+pub fn bench(_: TokenStream, input: TokenStream) -> TokenStream {
+    "struct Bench;".parse().unwrap()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs
new file mode 100644
index 00000000000..ff5984aa67c
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs
@@ -0,0 +1,22 @@
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn cfg(_: TokenStream, input: TokenStream) -> TokenStream {
+    //~^ ERROR name `cfg` is reserved in macro namespace
+    input
+}
+
+#[proc_macro_attribute]
+pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+    //~^ ERROR name `cfg_attr` is reserved in macro namespace
+    input
+}
+
+#[proc_macro_attribute]
+pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
+    //~^ ERROR name `derive` is reserved in macro namespace
+    input
+}
diff --git a/src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr
new file mode 100644
index 00000000000..be6e80c3878
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr
@@ -0,0 +1,20 @@
+error: name `cfg` is reserved in macro namespace
+  --> $DIR/reserved-macro-names.rs:7:8
+   |
+LL | pub fn cfg(_: TokenStream, input: TokenStream) -> TokenStream {
+   |        ^^^
+
+error: name `cfg_attr` is reserved in macro namespace
+  --> $DIR/reserved-macro-names.rs:13:8
+   |
+LL | pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+   |        ^^^^^^^^
+
+error: name `derive` is reserved in macro namespace
+  --> $DIR/reserved-macro-names.rs:19:8
+   |
+LL | pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
+   |        ^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr
deleted file mode 100644
index ed3e38486ba..00000000000
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: `foo` is not yet stable as a const fn
-  --> $DIR/dont_promote_unstable_const_fn.rs:25:25
-   |
-LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
-   |                         ^^^^^
-   |
-   = help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable
-
-error[E0597]: borrowed value does not live long enough
-  --> $DIR/dont_promote_unstable_const_fn.rs:33:26
-   |
-LL |     let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
-LL |     //~^ does not live long enough
-LL | }
-   | - temporary value only lives until here
-   |
-   = note: borrowed value must be valid for the static lifetime...
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr
deleted file mode 100644
index 4c8f2f47d1e..00000000000
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0597]: borrowed value does not live long enough
-  --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29
-   |
-LL |     let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
-   |                             ^^^^^ temporary value does not live long enough
-LL | }
-   | - temporary value only lives until here
-   |
-   = note: borrowed value must be valid for the static lifetime...
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/directory_ownership/mod_file_not_owning.stderr b/src/test/ui/directory_ownership/mod_file_not_owning.stderr
deleted file mode 100644
index e2937573997..00000000000
--- a/src/test/ui/directory_ownership/mod_file_not_owning.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660)
-  --> $DIR/mod_file_not_owning_aux1.rs:14:17
-   |
-LL |     () => { mod mod_file_not_owning_aux2; }
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
-LL | }
-LL | m!();
-   | ----- in this macro invocation
-   |
-   = help: add #![feature(non_modrs_mods)] to the crate attributes to enable
-   = help: on stable builds, rename this file to mod_file_not_owning_aux1/mod.rs
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/directory_ownership/unowned_mod_with_path.stderr b/src/test/ui/directory_ownership/unowned_mod_with_path.stderr
deleted file mode 100644
index 0c0b4281434..00000000000
--- a/src/test/ui/directory_ownership/unowned_mod_with_path.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660)
-  --> $DIR/mod_file_not_owning_aux1.rs:14:17
-   |
-LL |     () => { mod mod_file_not_owning_aux2; }
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
-LL | }
-LL | m!();
-   | ----- in this macro invocation
-   |
-   = help: add #![feature(non_modrs_mods)] to the crate attributes to enable
-   = help: on stable builds, rename this file to foo/mod.rs
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr b/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr
index c9b4f894ff6..0a0b1d573dd 100644
--- a/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr
+++ b/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr
@@ -1,17 +1,17 @@
-error[E0432]: unresolved import `a::$crate`
-  --> $DIR/dollar-crate-is-keyword-2.rs:15:13
+error[E0433]: failed to resolve. `$crate` in paths can only be used in start position
+  --> $DIR/dollar-crate-is-keyword-2.rs:16:16
    |
-LL |         use a::$crate; //~ ERROR unresolved import `a::$crate`
-   |             ^^^^^^^^^ no `$crate` in `a`
+LL |         use a::$crate::b; //~ ERROR `$crate` in paths can only be used in start position
+   |                ^^^^^^ `$crate` in paths can only be used in start position
 ...
 LL | m!();
    | ----- in this macro invocation
 
-error[E0433]: failed to resolve. `$crate` in paths can only be used in start position
-  --> $DIR/dollar-crate-is-keyword-2.rs:16:16
+error[E0432]: unresolved import `a::$crate`
+  --> $DIR/dollar-crate-is-keyword-2.rs:15:13
    |
-LL |         use a::$crate::b; //~ ERROR `$crate` in paths can only be used in start position
-   |                ^^^^^^ `$crate` in paths can only be used in start position
+LL |         use a::$crate; //~ ERROR unresolved import `a::$crate`
+   |             ^^^^^^^^^ no `$crate` in `a`
 ...
 LL | m!();
    | ----- in this macro invocation
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs b/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs
index 6c226799338..d0adcf4025f 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs
@@ -20,6 +20,8 @@
 // See issue-12997-1.rs and issue-12997-2.rs to see how `#[bench]` is
 // handled in "weird places" when `--test` is passed.
 
+#![feature(custom_inner_attributes)]
+
 #![bench                   = "4100"]
 
 fn main() { }
diff --git a/src/test/ui/feature-gates/feature-gate-linker-flavor.rs b/src/test/ui/feature-gates/feature-gate-linker-flavor.rs
index 955ec39cda1..711159647b7 100644
--- a/src/test/ui/feature-gates/feature-gate-linker-flavor.rs
+++ b/src/test/ui/feature-gates/feature-gate-linker-flavor.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -15,6 +15,5 @@
 
 #[used]
 fn foo() {}
-//~^^ ERROR the `#[used]` attribute is an experimental feature
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr b/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr
index b8bccece292..7019a666548 100644
--- a/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr
+++ b/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr
@@ -1,11 +1,8 @@
-error[E0658]: the `#[used]` attribute is an experimental feature (see issue #40289)
+error: attribute must be applied to a `static` variable
   --> $DIR/feature-gate-linker-flavor.rs:16:1
    |
 LL | #[used]
    | ^^^^^^^
-   |
-   = help: add #![feature(used)] to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-used.stderr b/src/test/ui/feature-gates/feature-gate-used.stderr
deleted file mode 100644
index d650b5ebb3b..00000000000
--- a/src/test/ui/feature-gates/feature-gate-used.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: the `#[used]` attribute is an experimental feature (see issue #40289)
-  --> $DIR/feature-gate-used.rs:11:1
-   |
-LL | #[used]
-   | ^^^^^^^
-   |
-   = help: add #![feature(used)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issue-53565.rs b/src/test/ui/issue-53565.rs
new file mode 100644
index 00000000000..2bf38296f26
--- /dev/null
+++ b/src/test/ui/issue-53565.rs
@@ -0,0 +1,14 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+use std::time::{foo, bar, buzz};
+use std::time::{abc, def};
+fn main(){
+   println!("Hello World!");
+}
diff --git a/src/test/ui/issue-53565.stderr b/src/test/ui/issue-53565.stderr
new file mode 100644
index 00000000000..945f5efe4a8
--- /dev/null
+++ b/src/test/ui/issue-53565.stderr
@@ -0,0 +1,20 @@
+error[E0432]: unresolved imports `std::time::foo`, `std::time::bar`, `std::time::buzz`
+  --> $DIR/issue-53565.rs:10:17
+   |
+LL | use std::time::{foo, bar, buzz};
+   |                 ^^^  ^^^  ^^^^ no `buzz` in `time`
+   |                 |    |
+   |                 |    no `bar` in `time`
+   |                 no `foo` in `time`
+
+error[E0432]: unresolved imports `std::time::abc`, `std::time::def`
+  --> $DIR/issue-53565.rs:11:17
+   |
+LL | use std::time::{abc, def};
+   |                 ^^^  ^^^ no `def` in `time`
+   |                 |
+   |                 no `abc` in `time`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/src/test/ui/issues/issue-11692-2.rs b/src/test/ui/issues/issue-11692-2.rs
index 424cbd981c8..2e94a27838e 100644
--- a/src/test/ui/issues/issue-11692-2.rs
+++ b/src/test/ui/issues/issue-11692-2.rs
@@ -9,6 +9,5 @@
 // except according to those terms.
 
 fn main() {
-    concat!(test!());
-    //~^ error: cannot find macro `test!` in this scope
+    concat!(test!()); //~ ERROR `test` can only be used in attributes
 }
diff --git a/src/test/ui/issues/issue-11692-2.stderr b/src/test/ui/issues/issue-11692-2.stderr
index 51d6041e922..186c59a6149 100644
--- a/src/test/ui/issues/issue-11692-2.stderr
+++ b/src/test/ui/issues/issue-11692-2.stderr
@@ -1,7 +1,7 @@
-error: cannot find macro `test!` in this scope
+error: `test` can only be used in attributes
   --> $DIR/issue-11692-2.rs:12:13
    |
-LL |     concat!(test!());
+LL |     concat!(test!()); //~ ERROR `test` can only be used in attributes
    |             ^^^^
 
 error: aborting due to previous error
diff --git a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs
index 84c305f5907..dd1c2a44730 100644
--- a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs
+++ b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs
@@ -20,8 +20,17 @@ fn make_it() -> for<'a> fn(&'a u32, &'a u32) -> &'a u32 {
     panic!()
 }
 
-fn main() {
+fn foo() {
     let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
     //~^ ERROR higher-ranked subtype error
     drop(a);
 }
+
+fn bar() {
+    // The code path for patterns is mildly different, so go ahead and
+    // test that too:
+    let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
+    //~^ ERROR higher-ranked subtype error
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
index e08d848b471..c9195395b87 100644
--- a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
+++ b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
@@ -4,5 +4,11 @@ error: higher-ranked subtype error
 LL |     let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
    |                                                          ^^^^^^^^^
 
-error: aborting due to previous error
+error: higher-ranked subtype error
+  --> $DIR/hr-fn-aaa-as-aba.rs:32:58
+   |
+LL |     let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
+   |                                                          ^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs b/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs
index 9b8268d9736..bc7b031f72c 100644
--- a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs
+++ b/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs
@@ -16,9 +16,7 @@
 // another -- effectively, the single lifetime `'a` is just inferred
 // to be the intersection of the two distinct lifetimes.
 //
-// FIXME: However, we currently reject this example with an error,
-// because of how we handle binders and equality in `relate_tys`.
-//
+// compile-pass
 // compile-flags:-Zno-leak-check
 
 #![feature(nll)]
@@ -31,7 +29,6 @@ fn make_cell_aa() -> Cell<for<'a> fn(&'a u32, &'a u32)> {
 
 fn aa_eq_ab() {
     let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
-    //~^ ERROR higher-ranked subtype error
     drop(a);
 }
 
diff --git a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr b/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr
deleted file mode 100644
index 17e8a32cb2a..00000000000
--- a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: higher-ranked subtype error
-  --> $DIR/hr-fn-aau-eq-abu.rs:33:53
-   |
-LL |     let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
-   |                                                     ^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/nll/relate_tys/universe-violation.rs b/src/test/ui/nll/relate_tys/universe-violation.rs
new file mode 100644
index 00000000000..cc86c8d02d3
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/universe-violation.rs
@@ -0,0 +1,17 @@
+// Test that the NLL `relate_tys` code correctly deduces that a
+// function returning either argument CANNOT be upcast to one
+// that returns always its first argument.
+//
+// compile-flags:-Zno-leak-check
+
+#![feature(nll)]
+
+fn make_it() -> fn(&'static u32) -> &'static u32 {
+    panic!()
+}
+
+fn main() {
+    let a: fn(_) -> _ = make_it();
+    let b: fn(&u32) -> &u32 = a;
+    drop(a);
+}
diff --git a/src/test/ui/nll/relate_tys/universe-violation.stderr b/src/test/ui/nll/relate_tys/universe-violation.stderr
new file mode 100644
index 00000000000..6dc78789564
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/universe-violation.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/universe-violation.rs:15:31
+   |
+LL |     let b: fn(&u32) -> &u32 = a;
+   |                               ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.rs b/src/test/ui/nll/relate_tys/var-appears-twice.rs
new file mode 100644
index 00000000000..02b3006c531
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/var-appears-twice.rs
@@ -0,0 +1,38 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the NLL `relate_tys` code correctly deduces that a
+// function returning always its first argument can be upcast to one
+// that returns either first or second argument.
+
+#![feature(nll)]
+#![allow(warnings)]
+
+use std::cell::Cell;
+
+type DoubleCell<A> = Cell<(A, A)>;
+type DoublePair<A> = (A, A);
+
+fn make_cell<'b>(x: &'b u32) -> Cell<(&'static u32, &'b u32)> {
+    panic!()
+}
+
+fn main() {
+    let a: &'static u32 = &22;
+    let b = 44;
+
+    // Here we get an error because `DoubleCell<_>` requires the same type
+    // on both parts of the `Cell`, and we can't have that.
+    let x: DoubleCell<_> = make_cell(&b); //~ ERROR
+
+    // Here we do not get an error because `DoublePair<_>` permits
+    // variance on the lifetimes involved.
+    let y: DoublePair<_> = make_cell(&b).get();
+}
diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.stderr b/src/test/ui/nll/relate_tys/var-appears-twice.stderr
new file mode 100644
index 00000000000..15c4cc2e100
--- /dev/null
+++ b/src/test/ui/nll/relate_tys/var-appears-twice.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `b` does not live long enough
+  --> $DIR/var-appears-twice.rs:33:38
+   |
+LL |     let x: DoubleCell<_> = make_cell(&b); //~ ERROR
+   |                                      ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `b` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/patterns.rs b/src/test/ui/nll/user-annotations/patterns.rs
new file mode 100644
index 00000000000..53d97360c86
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/patterns.rs
@@ -0,0 +1,121 @@
+// Test that various patterns also enforce types.
+
+#![feature(nll)]
+
+fn variable_no_initializer() {
+    let x = 22;
+    let y: &'static u32;
+    y = &x; //~ ERROR
+}
+
+fn tuple_no_initializer() {
+    // FIXME(#47187): We are not propagating ascribed type through tuples.
+
+    let x = 22;
+    let (y, z): (&'static u32, &'static u32);
+    y = &x;
+}
+
+fn ref_with_ascribed_static_type() -> u32 {
+    // Check the behavior in some wacky cases.
+    let x = 22;
+    let y = &x; //~ ERROR
+    let ref z: &'static u32 = y;
+    **z
+}
+
+fn ref_with_ascribed_any_type() -> u32 {
+    let x = 22;
+    let y = &x;
+    let ref z: &u32 = y;
+    **z
+}
+
+struct Single<T> { value: T }
+
+fn struct_no_initializer() {
+    // FIXME(#47187): We are not propagating ascribed type through patterns.
+
+    let x = 22;
+    let Single { value: y }: Single<&'static u32>;
+    y = &x;
+}
+
+fn variable_with_initializer() {
+    let x = 22;
+    let y: &'static u32 = &x; //~ ERROR
+}
+
+fn underscore_with_initializer() {
+    let x = 22;
+    let _: &'static u32 = &x; //~ ERROR
+
+    let _: Vec<&'static String> = vec![&String::new()];
+    //~^ ERROR borrowed value does not live long enough [E0597]
+
+    let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+    //~^ ERROR borrowed value does not live long enough [E0597]
+
+    let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+    //~^ ERROR borrowed value does not live long enough [E0597]
+}
+
+fn pair_underscores_with_initializer() {
+    let x = 22;
+    let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR
+}
+
+fn pair_variable_with_initializer() {
+    let x = 22;
+    let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
+}
+
+fn struct_single_field_variable_with_initializer() {
+    let x = 22;
+    let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
+}
+
+fn struct_single_field_underscore_with_initializer() {
+    let x = 22;
+    let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR
+}
+
+struct Double<T> { value1: T, value2: T }
+
+fn struct_double_field_underscore_with_initializer() {
+    let x = 22;
+    let Double { value1: _, value2: _ }: Double<&'static u32> = Double {
+        value1: &x, //~ ERROR
+        value2: &44,
+    };
+}
+
+fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
+    // The error in this test is inconsistency with
+    // `static_to_a_to_static_through_tuple`, but "feels right" to
+    // me. It occurs because we special case the single binding case
+    // and force the type of `y` to be `&'a u32`, even though the
+    // right-hand side has type `&'static u32`.
+
+    let y: &'a u32 = &22;
+    y //~ ERROR
+}
+
+fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
+    // FIXME(#47187): The fact that this type-checks is perhaps surprising.
+    // What happens is that the right-hand side is constrained to have
+    // type `&'a u32`, which is possible, because it has type
+    // `&'static u32`. The variable `y` is then forced to have type
+    // `&'static u32`, but it is constrained only by the right-hand
+    // side, not the ascribed type, and hence it passes.
+
+    let (y, _z): (&'a u32, u32) = (&22, 44);
+    y
+}
+
+fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
+    let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR
+    y
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr
new file mode 100644
index 00000000000..563de1a9e02
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/patterns.stderr
@@ -0,0 +1,143 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:8:9
+   |
+LL |     y = &x; //~ ERROR
+   |         ^^ borrowed value does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:22:13
+   |
+LL |     let y = &x; //~ ERROR
+   |             ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:46:27
+   |
+LL |     let y: &'static u32 = &x; //~ ERROR
+   |                           ^^ borrowed value does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:51:27
+   |
+LL |     let _: &'static u32 = &x; //~ ERROR
+   |                           ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/patterns.rs:53:41
+   |
+LL |     let _: Vec<&'static String> = vec![&String::new()];
+   |                                         ^^^^^^^^^^^^^ - temporary value only lives until here
+   |                                         |
+   |                                         temporary value does not live long enough
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/patterns.rs:56:52
+   |
+LL |     let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+   |                                                    ^^^^^^^^^^^^^      - temporary value only lives until here
+   |                                                    |
+   |                                                    temporary value does not live long enough
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/patterns.rs:59:53
+   |
+LL |     let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+   |                                                     ^^^^^^^^^^^^^      - temporary value only lives until here
+   |                                                     |
+   |                                                     temporary value does not live long enough
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:65:40
+   |
+LL |     let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR
+   |                                        ^^ borrowed value does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:70:40
+   |
+LL |     let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
+   |                                        ^^ borrowed value does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:75:69
+   |
+LL |     let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
+   |                                                                     ^^ borrowed value does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:80:69
+   |
+LL |     let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR
+   |                                                                     ^^ borrowed value does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/patterns.rs:88:17
+   |
+LL |         value1: &x, //~ ERROR
+   |                 ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: unsatisfied lifetime constraints
+  --> $DIR/patterns.rs:101:5
+   |
+LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
+   |                                           -- lifetime `'a` defined here
+...
+LL |     y //~ ERROR
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/patterns.rs:117:40
+   |
+LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
+   |                            -- lifetime `'a` defined here
+LL |     let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR
+   |                                        ^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/non_modrs_mods/non_modrs_mods.rs b/src/test/ui/non_modrs_mods/non_modrs_mods.rs
deleted file mode 100644
index 9dc85f4d3f9..00000000000
--- a/src/test/ui/non_modrs_mods/non_modrs_mods.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-//
-// Tests the formatting of the feature-gate errors for non_modrs_mods
-//
-// gate-test-non_modrs_mods
-// ignore-windows
-// ignore-pretty issue #37195
-pub mod modrs_mod;
-pub mod foors_mod;
-
-#[path = "some_crazy_attr_mod_dir/arbitrary_name.rs"]
-pub mod attr_mod;
-
-pub fn main() {
-    modrs_mod::inner_modrs_mod::innest::foo();
-    modrs_mod::inner_foors_mod::innest::foo();
-    foors_mod::inner_modrs_mod::innest::foo();
-    foors_mod::inner_foors_mod::innest::foo();
-    attr_mod::inner_modrs_mod::innest::foo();
-}
diff --git a/src/test/ui/non_modrs_mods/non_modrs_mods.stderr b/src/test/ui/non_modrs_mods/non_modrs_mods.stderr
deleted file mode 100644
index c45ab734fd5..00000000000
--- a/src/test/ui/non_modrs_mods/non_modrs_mods.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660)
-  --> $DIR/modrs_mod/inner_foors_mod.rs:11:9
-   |
-LL | pub mod innest;
-   |         ^^^^^^
-   |
-   = help: add #![feature(non_modrs_mods)] to the crate attributes to enable
-   = help: on stable builds, rename this file to inner_foors_mod/mod.rs
-
-error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660)
-  --> $DIR/foors_mod.rs:13:9
-   |
-LL | pub mod inner_modrs_mod;
-   |         ^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(non_modrs_mods)] to the crate attributes to enable
-   = help: on stable builds, rename this file to foors_mod/mod.rs
-
-error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660)
-  --> $DIR/foors_mod.rs:14:9
-   |
-LL | pub mod inner_foors_mod;
-   |         ^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(non_modrs_mods)] to the crate attributes to enable
-   = help: on stable builds, rename this file to foors_mod/mod.rs
-
-error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660)
-  --> $DIR/foors_mod/inner_foors_mod.rs:11:9
-   |
-LL | pub mod innest;
-   |         ^^^^^^
-   |
-   = help: add #![feature(non_modrs_mods)] to the crate attributes to enable
-   = help: on stable builds, rename this file to inner_foors_mod/mod.rs
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs
new file mode 100644
index 00000000000..339d49104b0
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs
@@ -0,0 +1,49 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2015
+
+// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
+// with examples easier.
+#![feature(irrefutable_let_patterns)]
+
+#[allow(irrefutable_let_patterns)]
+fn main() {
+    use std::ops::Range;
+
+    if let Range { start: _, end: _ } = true..true && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    if let Range { start: _, end: _ } = true..true || false { }
+    //~^ ERROR ambigious use of `||`
+
+    while let Range { start: _, end: _ } = true..true && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    while let Range { start: _, end: _ } = true..true || false { }
+    //~^ ERROR ambigious use of `||`
+
+    if let true = false && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    while let true = (1 == 2) && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    // The following cases are not an error as parenthesis are used to
+    // clarify intent:
+
+    if let Range { start: _, end: _ } = true..(true || false) { }
+
+    if let Range { start: _, end: _ } = true..(true && false) { }
+
+    while let Range { start: _, end: _ } = true..(true || false) { }
+
+    while let Range { start: _, end: _ } = true..(true && false) { }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr
new file mode 100644
index 00000000000..8597294913f
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr
@@ -0,0 +1,56 @@
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2015.rs:21:47
+   |
+LL |     if let Range { start: _, end: _ } = true..true && false { }
+   |                                               ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `||`
+  --> $DIR/syntax-ambiguity-2015.rs:24:47
+   |
+LL |     if let Range { start: _, end: _ } = true..true || false { }
+   |                                               ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2015.rs:27:50
+   |
+LL |     while let Range { start: _, end: _ } = true..true && false { }
+   |                                                  ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `||`
+  --> $DIR/syntax-ambiguity-2015.rs:30:50
+   |
+LL |     while let Range { start: _, end: _ } = true..true || false { }
+   |                                                  ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2015.rs:33:19
+   |
+LL |     if let true = false && false { }
+   |                   ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2015.rs:36:22
+   |
+LL |     while let true = (1 == 2) && false { }
+   |                      ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs
new file mode 100644
index 00000000000..baa90bcf8e9
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs
@@ -0,0 +1,49 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
+// with examples easier.
+#![feature(irrefutable_let_patterns)]
+
+#[allow(irrefutable_let_patterns)]
+fn main() {
+    use std::ops::Range;
+
+    if let Range { start: _, end: _ } = true..true && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    if let Range { start: _, end: _ } = true..true || false { }
+    //~^ ERROR ambigious use of `||`
+
+    while let Range { start: _, end: _ } = true..true && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    while let Range { start: _, end: _ } = true..true || false { }
+    //~^ ERROR ambigious use of `||`
+
+    if let true = false && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    while let true = (1 == 2) && false { }
+    //~^ ERROR ambigious use of `&&`
+
+    // The following cases are not an error as parenthesis are used to
+    // clarify intent:
+
+    if let Range { start: _, end: _ } = true..(true || false) { }
+
+    if let Range { start: _, end: _ } = true..(true && false) { }
+
+    while let Range { start: _, end: _ } = true..(true || false) { }
+
+    while let Range { start: _, end: _ } = true..(true && false) { }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr
new file mode 100644
index 00000000000..86ee04747b2
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr
@@ -0,0 +1,56 @@
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2018.rs:21:47
+   |
+LL |     if let Range { start: _, end: _ } = true..true && false { }
+   |                                               ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `||`
+  --> $DIR/syntax-ambiguity-2018.rs:24:47
+   |
+LL |     if let Range { start: _, end: _ } = true..true || false { }
+   |                                               ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2018.rs:27:50
+   |
+LL |     while let Range { start: _, end: _ } = true..true && false { }
+   |                                                  ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `||`
+  --> $DIR/syntax-ambiguity-2018.rs:30:50
+   |
+LL |     while let Range { start: _, end: _ } = true..true || false { }
+   |                                                  ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2018.rs:33:19
+   |
+LL |     if let true = false && false { }
+   |                   ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: ambigious use of `&&`
+  --> $DIR/syntax-ambiguity-2018.rs:36:22
+   |
+LL |     while let true = (1 == 2) && false { }
+   |                      ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
+   |
+   = note: this will be a error until the `let_chains` feature is stabilized
+   = note: see rust-lang/rust#53668 for more information
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/run-pass/issues/.gitattributes b/src/test/ui/run-pass/issues/.gitattributes
new file mode 100644
index 00000000000..4517a4a2f1e
--- /dev/null
+++ b/src/test/ui/run-pass/issues/.gitattributes
@@ -0,0 +1 @@
+issue-16278.rs -text
diff --git a/src/test/ui/run-pass/issues/issue-16278.rs b/src/test/ui/run-pass/issues/issue-16278.rs
index 831e83c8c4b..c3b6c5a38ba 100644
--- a/src/test/ui/run-pass/issues/issue-16278.rs
+++ b/src/test/ui/run-pass/issues/issue-16278.rs
@@ -13,8 +13,9 @@
 
 // this file has some special \r\n endings (use xxd to see them)
 
-fn main() {assert_eq!(b"", b"\
+fn main() {assert_eq!(b"", b"\

                                    ");
-assert_eq!(b"\n", b"
+assert_eq!(b"\n", b"

 ");
 }
+
diff --git a/src/test/ui/run-pass/issues/issue-41628.rs b/src/test/ui/run-pass/issues/issue-41628.rs
index 75924274f1c..f4b9588ff05 100644
--- a/src/test/ui/run-pass/issues/issue-41628.rs
+++ b/src/test/ui/run-pass/issues/issue-41628.rs
@@ -10,7 +10,6 @@
 
 // run-pass
 #![deny(dead_code)]
-#![feature(used)]
 
 #[used]
 static FOO: u32 = 0;
diff --git a/src/test/ui/run-pass/non_modrs_mods/non_modrs_mods.rs b/src/test/ui/run-pass/non_modrs_mods/non_modrs_mods.rs
deleted file mode 100644
index a9b240be804..00000000000
--- a/src/test/ui/run-pass/non_modrs_mods/non_modrs_mods.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// run-pass
-//
-// ignore-pretty issue #37195
-#![feature(non_modrs_mods)]
-
-pub mod modrs_mod;
-pub mod foors_mod;
-
-#[path = "some_crazy_attr_mod_dir/arbitrary_name.rs"]
-pub mod attr_mod;
-
-pub fn main() {
-    modrs_mod::inner_modrs_mod::innest::foo();
-    modrs_mod::inner_foors_mod::innest::foo();
-    foors_mod::inner_modrs_mod::innest::foo();
-    foors_mod::inner_foors_mod::innest::foo();
-    attr_mod::inner_modrs_mod::innest::foo();
-}
diff --git a/src/test/ui/rust-2018/async-ident.fixed b/src/test/ui/rust-2018/async-ident.fixed
index ef88f835fc8..125e7c3773a 100644
--- a/src/test/ui/rust-2018/async-ident.fixed
+++ b/src/test/ui/rust-2018/async-ident.fixed
@@ -26,7 +26,9 @@ macro_rules! foo {
     //~| WARN hard error in the 2018 edition
 }
 
-foo!(async);
+foo!(r#async);
+    //~^ ERROR async
+    //~| WARN hard error in the 2018 edition
 
 mod dont_lint_raw {
     fn r#async() {}
diff --git a/src/test/ui/rust-2018/async-ident.rs b/src/test/ui/rust-2018/async-ident.rs
index 069da7ffcdd..01b974bcbfb 100644
--- a/src/test/ui/rust-2018/async-ident.rs
+++ b/src/test/ui/rust-2018/async-ident.rs
@@ -27,6 +27,8 @@ macro_rules! foo {
 }
 
 foo!(async);
+    //~^ ERROR async
+    //~| WARN hard error in the 2018 edition
 
 mod dont_lint_raw {
     fn r#async() {}
diff --git a/src/test/ui/rust-2018/async-ident.stderr b/src/test/ui/rust-2018/async-ident.stderr
index b9bb2e254b4..46e6af84ab8 100644
--- a/src/test/ui/rust-2018/async-ident.stderr
+++ b/src/test/ui/rust-2018/async-ident.stderr
@@ -31,7 +31,16 @@ LL |     ($async:expr, async) => {};
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:36:11
+  --> $DIR/async-ident.rs:29:6
+   |
+LL | foo!(async);
+   |      ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `async` is a keyword in the 2018 edition
+  --> $DIR/async-ident.rs:38:11
    |
 LL |     trait async {}
    |           ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -40,7 +49,7 @@ LL |     trait async {}
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:40:10
+  --> $DIR/async-ident.rs:42:10
    |
 LL |     impl async for MyStruct {}
    |          ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -49,7 +58,7 @@ LL |     impl async for MyStruct {}
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:46:12
+  --> $DIR/async-ident.rs:48:12
    |
 LL |     static async: u32 = 0;
    |            ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -58,7 +67,7 @@ LL |     static async: u32 = 0;
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:52:11
+  --> $DIR/async-ident.rs:54:11
    |
 LL |     const async: u32 = 0;
    |           ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -67,7 +76,7 @@ LL |     const async: u32 = 0;
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:58:15
+  --> $DIR/async-ident.rs:60:15
    |
 LL | impl Foo { fn async() {} }
    |               ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -76,7 +85,7 @@ LL | impl Foo { fn async() {} }
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:63:12
+  --> $DIR/async-ident.rs:65:12
    |
 LL |     struct async {}
    |            ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -85,7 +94,7 @@ LL |     struct async {}
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:66:9
+  --> $DIR/async-ident.rs:68:9
    |
 LL |     let async: async = async {};
    |         ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -94,7 +103,7 @@ LL |     let async: async = async {};
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:66:16
+  --> $DIR/async-ident.rs:68:16
    |
 LL |     let async: async = async {};
    |                ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -103,7 +112,7 @@ LL |     let async: async = async {};
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:66:24
+  --> $DIR/async-ident.rs:68:24
    |
 LL |     let async: async = async {};
    |                        ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -112,7 +121,7 @@ LL |     let async: async = async {};
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:77:19
+  --> $DIR/async-ident.rs:79:19
    |
 LL |     () => (pub fn async() {})
    |                   ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -121,7 +130,7 @@ LL |     () => (pub fn async() {})
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:84:6
+  --> $DIR/async-ident.rs:86:6
    |
 LL |     (async) => (1)
    |      ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -129,5 +138,5 @@ LL |     (async) => (1)
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/test/ui/rust-2018/try-macro.fixed b/src/test/ui/rust-2018/try-macro.fixed
new file mode 100644
index 00000000000..c65f0fc30ef
--- /dev/null
+++ b/src/test/ui/rust-2018/try-macro.fixed
@@ -0,0 +1,16 @@
+// Test that `try!` macros are rewritten.
+
+// run-rustfix
+// compile-pass
+
+#![warn(rust_2018_compatibility)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+fn foo() -> Result<usize, ()> {
+    let x: Result<usize, ()> = Ok(22);
+    r#try!(x);
+    Ok(44)
+}
+
+fn main() { }
diff --git a/src/test/ui/rust-2018/try-macro.rs b/src/test/ui/rust-2018/try-macro.rs
new file mode 100644
index 00000000000..f435890a61d
--- /dev/null
+++ b/src/test/ui/rust-2018/try-macro.rs
@@ -0,0 +1,16 @@
+// Test that `try!` macros are rewritten.
+
+// run-rustfix
+// compile-pass
+
+#![warn(rust_2018_compatibility)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+fn foo() -> Result<usize, ()> {
+    let x: Result<usize, ()> = Ok(22);
+    try!(x);
+    Ok(44)
+}
+
+fn main() { }
diff --git a/src/test/ui/rust-2018/try-macro.stderr b/src/test/ui/rust-2018/try-macro.stderr
new file mode 100644
index 00000000000..40a4564cc3d
--- /dev/null
+++ b/src/test/ui/rust-2018/try-macro.stderr
@@ -0,0 +1,15 @@
+warning: `try` is a keyword in the 2018 edition
+  --> $DIR/try-macro.rs:12:5
+   |
+LL |     try!(x);
+   |     ^^^ help: you can use a raw identifier to stay compatible: `r#try`
+   |
+note: lint level defined here
+  --> $DIR/try-macro.rs:6:9
+   |
+LL | #![warn(rust_2018_compatibility)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: #[warn(keyword_idents)] implied by #[warn(rust_2018_compatibility)]
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs
new file mode 100644
index 00000000000..590e83b0781
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+// This test is similar to `ambiguity-macros.rs`, but nested in a module.
+
+mod foo {
+    pub use std::io;
+    //~^ ERROR `std` import is ambiguous
+
+    macro_rules! m {
+        () => {
+            mod std {
+                pub struct io;
+            }
+        }
+    }
+    m!();
+}
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr
new file mode 100644
index 00000000000..948043cff76
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr
@@ -0,0 +1,16 @@
+error: `std` import is ambiguous
+  --> $DIR/ambiguity-macros-nested.rs:16:13
+   |
+LL |       pub use std::io;
+   |               ^^^ can refer to external crate `::std`
+...
+LL | /             mod std {
+LL | |                 pub struct io;
+LL | |             }
+   | |_____________- may refer to `self::std` in the future
+   |
+   = help: write `::std` or `self::std` explicitly instead
+   = note: in the future, `#![feature(uniform_paths)]` may become the default
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs
new file mode 100644
index 00000000000..861efba14f8
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs
@@ -0,0 +1,27 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+// This test is similar to `ambiguity.rs`, but with macros defining local items.
+
+use std::io;
+//~^ ERROR `std` import is ambiguous
+
+macro_rules! m {
+    () => {
+        mod std {
+            pub struct io;
+        }
+    }
+}
+m!();
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr
new file mode 100644
index 00000000000..40cceea2440
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr
@@ -0,0 +1,16 @@
+error: `std` import is ambiguous
+  --> $DIR/ambiguity-macros.rs:15:5
+   |
+LL |   use std::io;
+   |       ^^^ can refer to external crate `::std`
+...
+LL | /         mod std {
+LL | |             pub struct io;
+LL | |         }
+   | |_________- may refer to `self::std` in the future
+   |
+   = help: write `::std` or `self::std` explicitly instead
+   = note: in the future, `#![feature(uniform_paths)]` may become the default
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs
new file mode 100644
index 00000000000..a69eb101917
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs
@@ -0,0 +1,24 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+// This test is similar to `ambiguity.rs`, but nested in a module.
+
+mod foo {
+    pub use std::io;
+    //~^ ERROR `std` import is ambiguous
+
+    mod std {
+        pub struct io;
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr
new file mode 100644
index 00000000000..7538d3d2d91
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr
@@ -0,0 +1,16 @@
+error: `std` import is ambiguous
+  --> $DIR/ambiguity-nested.rs:16:13
+   |
+LL |       pub use std::io;
+   |               ^^^ can refer to external crate `::std`
+...
+LL | /     mod std {
+LL | |         pub struct io;
+LL | |     }
+   | |_____- may refer to `self::std` in the future
+   |
+   = help: write `::std` or `self::std` explicitly instead
+   = note: in the future, `#![feature(uniform_paths)]` may become the default
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/directory_ownership/mod_file_not_owning.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs
index ff93fddf9b3..500e9f6c63f 100644
--- a/src/test/ui/directory_ownership/mod_file_not_owning.rs
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,8 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: mod statements in non-mod.rs files are unstable
+// edition:2018
 
-mod mod_file_not_owning_aux1;
+use std::io;
+//~^ ERROR `std` import is ambiguous
+
+mod std {
+    pub struct io;
+}
 
 fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr
new file mode 100644
index 00000000000..7b64b8f0246
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr
@@ -0,0 +1,16 @@
+error: `std` import is ambiguous
+  --> $DIR/ambiguity.rs:13:5
+   |
+LL |   use std::io;
+   |       ^^^ can refer to external crate `::std`
+...
+LL | / mod std {
+LL | |     pub struct io;
+LL | | }
+   | |_- may refer to `self::std` in the future
+   |
+   = help: write `::std` or `self::std` explicitly instead
+   = note: in the future, `#![feature(uniform_paths)]` may become the default
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/directory_ownership/unowned_mod_with_path.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs
index 0cffb7cc9e5..ca488fec516 100644
--- a/src/test/ui/directory_ownership/unowned_mod_with_path.rs
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,8 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: mod statements in non-mod.rs files are unstable
+// edition:2018
 
-// This is not a directory owner since the file name is not "mod.rs".
-#[path = "mod_file_not_owning_aux1.rs"]
-mod foo;
+struct std;
+
+fn main() {
+    fn std() {}
+    enum std {}
+    use std as foo;
+    //~^ ERROR `std` import is ambiguous
+    //~| ERROR `std` import is ambiguous
+}
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr
new file mode 100644
index 00000000000..27e0e883691
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr
@@ -0,0 +1,31 @@
+error: `std` import is ambiguous
+  --> $DIR/block-scoped-shadow.rs:18:9
+   |
+LL | struct std;
+   | ----------- may refer to `self::std` in the future
+...
+LL |     enum std {}
+   |     ----------- shadowed by block-scoped `std`
+LL |     use std as foo;
+   |         ^^^ can refer to external crate `::std`
+   |
+   = help: write `::std` or `self::std` explicitly instead
+   = note: in the future, `#![feature(uniform_paths)]` may become the default
+
+error: `std` import is ambiguous
+  --> $DIR/block-scoped-shadow.rs:18:9
+   |
+LL | struct std;
+   | ----------- may refer to `self::std` in the future
+...
+LL |     fn std() {}
+   |     ----------- shadowed by block-scoped `std`
+LL |     enum std {}
+LL |     use std as foo;
+   |         ^^^
+   |
+   = help: write `self::std` explicitly instead
+   = note: in the future, `#![feature(uniform_paths)]` may become the default
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/redundant.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/redundant.rs
new file mode 100644
index 00000000000..05048cfd451
--- /dev/null
+++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/redundant.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// edition:2018
+
+use std;
+use std::io;
+
+mod foo {
+    pub use std as my_std;
+}
+
+mod bar {
+    pub use std::{self};
+}
+
+fn main() {
+    io::stdout();
+    self::std::io::stdout();
+    foo::my_std::io::stdout();
+    bar::std::io::stdout();
+}
diff --git a/src/test/run-pass/redundant.rs b/src/test/ui/rust-2018/uniform-paths/redundant.rs
index 39bd3160695..745ac18e059 100644
--- a/src/test/run-pass/redundant.rs
+++ b/src/test/ui/rust-2018/uniform-paths/redundant.rs
@@ -8,11 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-pass
 // edition:2018
 
 #![feature(uniform_paths)]
 
 use std;
+use std::io;
 
 mod foo {
     pub use std as my_std;
@@ -23,6 +25,7 @@ mod bar {
 }
 
 fn main() {
+    io::stdout();
     self::std::io::stdout();
     foo::my_std::io::stdout();
     bar::std::io::stdout();
diff --git a/src/test/ui/span/issue-36530.rs b/src/test/ui/span/issue-36530.rs
index c6cdb8b6db7..fbe1535caae 100644
--- a/src/test/ui/span/issue-36530.rs
+++ b/src/test/ui/span/issue-36530.rs
@@ -8,7 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// gate-test-custom_inner_attributes
+
 #[foo] //~ ERROR is currently unknown to the compiler
 mod foo {
     #![foo] //~ ERROR is currently unknown to the compiler
+            //~| ERROR non-builtin inner attributes are unstable
 }
diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr
index e7dd8e7aa8f..78d81ad0493 100644
--- a/src/test/ui/span/issue-36530.stderr
+++ b/src/test/ui/span/issue-36530.stderr
@@ -1,19 +1,27 @@
 error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/issue-36530.rs:11:3
+  --> $DIR/issue-36530.rs:13:3
    |
 LL | #[foo] //~ ERROR is currently unknown to the compiler
    |   ^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
+error[E0658]: non-builtin inner attributes are unstable (see issue #38356)
+  --> $DIR/issue-36530.rs:15:5
+   |
+LL |     #![foo] //~ ERROR is currently unknown to the compiler
+   |     ^^^^^^^
+   |
+   = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable
+
 error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/issue-36530.rs:13:8
+  --> $DIR/issue-36530.rs:15:8
    |
 LL |     #![foo] //~ ERROR is currently unknown to the compiler
    |        ^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/test-shadowing/test-cant-be-shadowed.rs b/src/test/ui/test-shadowing/test-cant-be-shadowed.rs
index 4b1a437818f..4e24b17bdd5 100644
--- a/src/test/ui/test-shadowing/test-cant-be-shadowed.rs
+++ b/src/test/ui/test-shadowing/test-cant-be-shadowed.rs
@@ -16,3 +16,8 @@
 
 #[test]
 fn foo(){}
+
+macro_rules! test { () => () }
+
+#[test]
+fn bar() {}
diff --git a/src/test/ui/try-block/try-block-bad-lifetime.stderr b/src/test/ui/try-block/try-block-bad-lifetime.stderr
index 36c89faf5a2..ebf56dc9835 100644
--- a/src/test/ui/try-block/try-block-bad-lifetime.stderr
+++ b/src/test/ui/try-block/try-block-bad-lifetime.stderr
@@ -1,13 +1,14 @@
 error[E0597]: `my_string` does not live long enough
   --> $DIR/try-block-bad-lifetime.rs:25:33
    |
+LL |         let result: Result<(), &str> = try {
+   |             ------ borrow later used here
+LL |             let my_string = String::from("");
 LL |             let my_str: & str = & my_string;
    |                                 ^^^^^^^^^^^ borrowed value does not live long enough
 ...
 LL |         };
    |         - `my_string` dropped here while still borrowed
-LL |         do_something_with(result);
-   |                           ------ borrow later used here
 
 error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-bad-lifetime.rs:39:13
diff --git a/src/test/ui/used.rs b/src/test/ui/used.rs
index f170d9c25f5..b3ed8601988 100644
--- a/src/test/ui/used.rs
+++ b/src/test/ui/used.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(used)]
-
 #[used]
 static FOO: u32 = 0; // OK
 
diff --git a/src/test/ui/used.stderr b/src/test/ui/used.stderr
index b8d0f42c3a3..351fb940426 100644
--- a/src/test/ui/used.stderr
+++ b/src/test/ui/used.stderr
@@ -1,23 +1,23 @@
 error: attribute must be applied to a `static` variable
-  --> $DIR/used.rs:16:1
+  --> $DIR/used.rs:14:1
    |
 LL | #[used] //~ ERROR attribute must be applied to a `static` variable
    | ^^^^^^^
 
 error: attribute must be applied to a `static` variable
-  --> $DIR/used.rs:19:1
+  --> $DIR/used.rs:17:1
    |
 LL | #[used] //~ ERROR attribute must be applied to a `static` variable
    | ^^^^^^^
 
 error: attribute must be applied to a `static` variable
-  --> $DIR/used.rs:22:1
+  --> $DIR/used.rs:20:1
    |
 LL | #[used] //~ ERROR attribute must be applied to a `static` variable
    | ^^^^^^^
 
 error: attribute must be applied to a `static` variable
-  --> $DIR/used.rs:25:1
+  --> $DIR/used.rs:23:1
    |
 LL | #[used] //~ ERROR attribute must be applied to a `static` variable
    | ^^^^^^^
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 2fb77a49b43bf7266793c07a19a06749e6a8ad5
+Subproject b917e35248fe57d11765c5a835de33e335babb7
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 5b5cd9d45719414196e254ec17baa598acc8cd2
+Subproject fa922de1e5e1f02b576b7a5aa6ded16935693ec