about summary refs log tree commit diff
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
parent8134ee25b88df98c79792d60cbf6745b6cb7ffc5 (diff)
parent8586ec6980462c99a8926646201b2444d8938d29 (diff)
Merge branch 'master' into kenta7777#53719
-rw-r--r--README.md6
-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
157 files changed, 3528 insertions, 1899 deletions
diff --git a/README.md b/README.md
index a2acfe8b478..0e5b7170bc6 100644
--- a/README.md
+++ b/README.md
@@ -125,9 +125,9 @@ you have a more recent version installed the build system doesn't understand
 then you may need to force rustbuild to use an older version. This can be done
 by manually calling the appropriate vcvars file before running the bootstrap.
 
-```
-CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
-python x.py build
+```batch
+> CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
+> python x.py build
 ```
 
 #### Specifying an ABI
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